Step 1: revised catch for 2010-2020 Step 2: tune resilience of all the species (i.e., long-lived, slower growing species = vulnerable…etc…) Step 3: calibrated model with fishing mortality represented (time-averaged catch comparison, model vs observed) = base model Step 4: check base model without fishing to ensure co-existence is still present, observed biomass would not be specified Step 5: Experiments through time - effort functions - uses the base model with no fishing effort as a starting point Step 6: Expose the base model to fishing through time and compare to observed catch time series - start from 0 effort at first time-step to max effort approx around collapse - If the modelled versus observed don’t match, need to adjust effort/or initial biological params and experiment to see what improves - hand tune / optim options Adjust and recalibrate if needed (optim) Use rules to constrain - i.e., - time-averaged biomasses within calibration period must be +- xx % - can optim things like fishing-size selectivity, PPMRs etc

Can we reproduce the time series?

Load libraries

remotes::install_github("sizespectrum/mizerExperimental")
Skipping install of 'mizerExperimental' from a github remote, the SHA1 (8279ac0d) has not changed since last install.
  Use `force = TRUE` to force installation
library(mizerExperimental)
# remotes::install_github("sizespectrum/mizerMR")
# library(mizerMR)
# library(mizer)
library(tidyverse)
Warning: package ‘tidyverse’ was built under R version 4.2.3Warning: package ‘ggplot2’ was built under R version 4.2.3Warning: package ‘readr’ was built under R version 4.2.3Warning: package ‘forcats’ was built under R version 4.2.3── Attaching core tidyverse packages ──────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.0     ✔ readr     2.1.4
✔ forcats   1.0.0     ✔ stringr   1.5.0
✔ ggplot2   3.4.2     ✔ tibble    3.1.7
✔ lubridate 1.9.2     ✔ tidyr     1.3.0
✔ purrr     1.0.1     ── Conflicts ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(tictoc)
library(parallel)
# library(plotly)

Catch data for all indivudals and summarised as totals per species each year

Maybe this isn’t expressing effort, rather fishing mortality

# df_ind_CPUE <- readRDS("ind_catch_weight_BanzareBank_1930_2019_CPUE.rds")
# df_CPUE_kg_day <- readRDS("catch_timeseries_BanzareBank_1930_2019_CPUE.rds")
# 
# glimpse(df_ind_CPUE)
# glimpse(df_CPUE_kg_day)

Yield for the period that matches Ecopath model, post 2000 annual average

# df_yield_2000 <- df_CPUE_kg_day %>% 
#   filter(Year > 2009) %>% 
#   group_by(Species) %>% 
#   summarise(yield = sum(total_catch_kg)/10)
# 
# df_yield_2000

effort_days/max value plotted by species This might indicate the effort curve required, especially if there is a difference between different species

# df_plot <- df_CPUE_kg_day %>% 
#   filter(Year > 2000) %>% 
#   group_by(Species) %>% 
#   mutate(max_effort = max(effort_days)) %>% 
#   group_by(Species,Year) %>% 
#   mutate(effort_standard = effort_days/max_effort)

Relative change in catch pre-1930, could inform the relative change in effort Ask Cami, how could I reconstruct the effort to the initial point of catch when effort = 0…i.e., approx 1850

# df_plot %>% 
#   ggplot(aes(x = Year, y = effort_standard, colour = Species)) +
#   geom_smooth() +
#   geom_line()
#   # facet_wrap(~Species) 
# df_plot %>% 
#   ggplot(aes(x = Year, y = CPUE, colour = Species)) +
#   # geom_smooth() +
#   geom_line()
#   # facet_wrap(~Species) 

Load catch length

catch_lengths <- readRDS("catch_lengths.rds")

glimpse(catch_lengths)

The value for euphausiids obs_yield is from calibration_catch_histsoc_1850_2004_regional_models.csv found at http://portal.sf.utas.edu.au/thredds/catalog/gem/fishmip/ISIMIP3a/InputData/fishing/histsoc/catalog.html. It is the annual average yield over a 22 year period for the Prydz Bay Region.

The values of obs_yield for minke whales (2175476136), orca (19923729), sperm whales (4062177445), and baleen whales (50341696055) are the annual average yield from 1930 - 2019 from IWC records of whaling in the Prydz Bay model domain (1,433,028 km2).

Adjust the catch to represent the 2010 - 2020 time period + incorporate toothfish catch if possible (i.e., Stacey’s paper values)

df_ind_CPUE <- readRDS("ind_catch_weight_BanzareBank_1930_2019_CPUE.rds")
df_CPUE_kg_day <- readRDS("catch_timeseries_BanzareBank_1930_2019_CPUE.rds")

glimpse(df_ind_CPUE)
glimpse(df_CPUE_kg_day)

Yield for the period that matches Ecopath model, post 2000 annual average

df_yield_2000_2019 <- df_CPUE_kg_day %>% 
  filter(Year > 2000) %>% 
  group_by(Species) %>% 
  summarise(yield = sum(total_catch_kg)/19)

df_yield_2000_2019

Add yield in tonnes per km2, same as g m2 and it is consistent with biomass_observed

1.474341e+12 m^2 for model domain

1.474341e+12/1e+6 = 1474341 km^2

507511 kg of minke whale per year from 2000 - 2019

507.5/1474341 = 0.0003442216 tonnes Minke whale yield per km2 from 2000 - 2019

15619.24 kg of baleen whale per year from 2000 - 2019

15.6/1474341 = 1.0581e-05 tonnes of baleen whale per km2 from 2000 - 2019

obs_yield <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0003442216, 0, 0, 1.0581e-05) # to add a yield_observed column in species_params
biomass_cutoff <- c(0.1, 1, 1, 1, 40, 4500, 1, 1, 200000, 10000, 135000, 600000, 490000, 3650000, 2250000) # to add a biomass_cutoff column in species_params

Steady-state model with no fishing effort calibrated to observed biomass values from McCormack et al. 2020 that represent an average state of the food web from 2010-2020.

# params <-  readRDS("stage1_steady_vXX.rds") # Incorrect orca and leopard seal w_max values
so_params <- readRDS("params_16_March_2023.rds") # Updated w_max for orca and leopard seals

# params <- setParams(setFishing(params, initial_effort = 0.2))
# species_params(params)$yield_observed <- obs_yield
# species_params(params)$biomass_cutoff <- biomass_cutoff
# species_params(params)$biomass_cutoffLow <- biomass_cutoff
# species_params(params)$biomass_cutoffHigh <- species_params(params)$w_max

species_params(so_params)$yield_observed <- obs_yield
species_params(so_params)$biomass_cutoff <- biomass_cutoff
species_params(so_params)$biomass_cutoffLow <- biomass_cutoff
species_params(so_params)$biomass_cutoffHigh <- species_params(so_params)$w_max

# species_params(params) |> dplyr::select(species, yield_observed, w_mat, w_max, R_max)
species_params(so_params) |> dplyr::select(species, yield_observed, w_mat, w_max, R_max)
# groups |> dplyr::select(species, yield_observed, biomass_observed, biomass_cutoff, w_min)
# yield_observed <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0003442216, 0, 0, 1.0581e-05) # to add a yield_observed column in species_params
# 
# species_params(params)$yield_observed <- yield_observed
# biomass_cutoff <- c(0.1, 1, 1, 1, 40, 4500, 1, 1, 200000, 10000, 135000, 600000, 490000, 3650000, 2250000) # to add a biomass_cutoff column in species_params
# 
# species_params(params)$biomass_cutoff <- biomass_cutoff

Update max and mat size for orca using sealifebase values rather than the previous w_max of 6t

# species_params(params)$species[13]
# species_params(params)$w_max[13]
# species_params(params)$w_mat[13]
# 
# species_params(params)$w_max[13] <- 10628034
# 
# species_params(params)$w_mat[13] <- 3198855
# 
# species_params(params)$w_max[13]
# species_params(params)$w_mat[13]
# species_params(params)$w_mat25[13]

Update max and mat size for leopard seal using sealifebase values. Max weight observed reported as 450kg. Using the sealifebase values for L-W conversion and max length results in an estimated max weight of 545875.2g, which is too high above the max weight observed.

# species_params(params)$species[9]
# species_params(params)$w_max[9]
# species_params(params)$w_mat[9]
# 
# species_params(params)$w_max[9] <- 450000
#  
# species_params(params)$w_max[9]
# species_params(params)$w_mat[9]
# species_params(params)$w_mat25[9]

Adjust w_mat values that were changed by default in newMultispeciesParams

# params_v1 <- params
# 
# params_v1@species_params$w_mat[params_v1@species_params$species == "large divers"]  <- params_v1@species_params$w_max[params_v1@species_params$species == "large divers"] * 0.9
# params_v1@species_params$w_mat[params_v1@species_params$species == "minke whales"]  <- params_v1@species_params$w_max[params_v1@species_params$species == "minke whales"] * 0.9
# params_v1@species_params$w_mat[params_v1@species_params$species == "orca"]  <- params_v1@species_params$w_max[params_v1@species_params$species == "orca"] * 0.9
# params_v1@species_params$w_mat[params_v1@species_params$species == "sperm whales"]  <- params_v1@species_params$w_max[params_v1@species_params$species == "sperm whales"] * 0.9
# 
# params_v1 <- setParams(params_v1)
# params_v2 <- params_v1
# 
# params_v2@species_params$w_min[params_v2@species_params$species == "small divers"]  <- params_v2@species_params$w_mat[params_v2@species_params$species == "small divers"] * 0.85
# params_v2@species_params$w_min[params_v2@species_params$species == "leopard seals"]  <- params_v2@species_params$w_mat[params_v2@species_params$species == "leopard seals"] * 0.85
# 
# params_v2 <- setParams(params_v2)
params <- steady(so_params)

Check gear params

gear_params(params)

Adjust catchability to only select fishing on species with catch data This is a only starting point

gear_params(params)$catchability <-  c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.49, 0, 0, 0.001)

Catchability: 1 value Effort changes through time (voyage frequency and length)

gear_params(params)$gear <-  c("Main", "Main", "Main", "Main", "Main", "Main",
                                   "Main", "Main", "Main", "Main", "Main", "Main",
                                   "Main", "Main", "Main")

gear_params(params)$l50 <-  c(1, 5, 5, 5, 10, 10, 10, 20, 20, 20, 20, 850, 600, 1500, 2200) # values for minke, orca, sperm and baleen are estimated based off `catch_lengths`, while all others are rough guesses, purely as the param won't work with values missing.

gear_params(params)$l25 <-  c(0.8, 4, 4, 4, 8, 8, 8, 16, 16, 16, 16, 800, 500, 1400, 1500)

gear_params(params)$sel_func <-  c("sigmoid_length", "sigmoid_length", "sigmoid_length", "sigmoid_length", "sigmoid_length", "sigmoid_length",
                                   "sigmoid_length", "sigmoid_length", "sigmoid_length", "sigmoid_length", "sigmoid_length", "sigmoid_length",
                                   "sigmoid_length", "sigmoid_length", "sigmoid_length")

gear_params(params)
params_v02 <- setParams(setFishing(params, initial_effort = 0.2))

params_v02 <- steady(params_v02)

sim_v01 <- project(params_v02, t_max = 100)
plot(sim_v01)
plotlyBiomass(sim_v01)
sim_v01@params@initial_effort
plotYieldVsSize(sim_v01, species = "baleen whales", catch = catch_lengths, 
                x_var = "Length")

# plotYieldVsSize(sim_v1, species = "sperm whales", catch = catch_lengths, 
#                 x_var = "Length")
# 
# plotYieldVsSize(sim_v1, species = "orca", catch = catch_lengths, 
#                 x_var = "Length")

plotYieldVsSize(sim_v01, species = "minke whales", catch = catch_lengths, 
                x_var = "Length")
getErrorCustom <- function(vary, params, dat, tol = 0.001, 
    timetorun = 10)
{
  params@species_params$R_max[1:15]<-10^vary[1:15] # R_max for 15 species
  params@species_params$erepro[1:15]<-vary[16:30] # erepro for 15 species
  params@species_params$interaction_resource[1:15] <- vary[31:45] # interaction_resource for 15 species
  params <- setParams(params)
  # interaction <- params@interaction
  # interaction[] <- matrix(vary[28:108],nrow = 9) # stop at 54 if looking only at 3 biggest species
  
  # params <- setInteraction(params,interaction)
    params <- projectToSteady(params, distance_func = distanceSSLogN, 
        tol = tol, t_max = 200, return_sim = F)
    
    sim <- project(params, t_max = timetorun, progress_bar = F)
    
    sim_biomass = rep(0, length(params@species_params$species))
    
        cutoffLow <- params@species_params$biomass_cutoffLow
    if (is.null(cutoffLow)) 
        cutoffLow <- rep(0, no_sp)
    cutoffLow[is.na(cutoffLow)] <- 0
    
        cutoffHigh <- params@species_params$biomass_cutoffHigh
    if (is.null(cutoffHigh)) 
        cutoffHigh <- rep(0, no_sp)
    cutoffHigh[is.na(cutoffHigh)] <- 0
        
    for (j in 1:length(sim_biomass)) {
        sim_biomass[j] = sum((sim@n[dim(sim@n)[1],j,] * params@w * 
            params@dw)[params@w >= cutoffLow[j] & cutoffHigh[j] >= params@w])
    }
    
     pred <- log(sim_biomass)
    dat <- log(dat)
    discrep <- pred - dat
    discrep <- (sum(discrep^2))
    return(discrep)
}
    
# create set of params for the optimisation process
tic()

params_optim <- params_v02

vary <- c(log10(params_optim@species_params$R_max),
          params_optim@species_params$erepro,
          params_optim@species_params$interaction_resource)

params_optim<-setParams(params_optim)

# set up workers
noCores <- parallel::detectCores() - 1 # keep some spare core
cl <- parallel::makeCluster(noCores, setup_timeout = 0.5)
setDefaultCluster(cl = cl)
clusterExport(cl, varlist = "cl",envir=environment())
clusterEvalQ(cl, {
  library(mizerExperimental)
  library(optimParallel)
})

optim_result <- optimParallel::optimParallel(par=vary,getErrorCustom,params=params_optim, 
                                             dat = params_optim@species_params$biomass_observed, method ="L-BFGS-B", 
                                             lower=c(rep(-15,15),rep(1e-7,15),rep(.1,15)),
                                             upper= c(rep(15,15),rep(1,15),rep(.99,15)),
                                             parallel=list(loginfo=TRUE, forward=TRUE))
stopCluster(cl)

toc()

saveRDS(optim_result, file="optim_result_v00.RDS")
# optim_result <- readRDS("optim_result_v00.RDS")
#put these new vals intospecies_params and go back to the top of this page to re-check the calibration 
species_params(params_optim)$R_max<-10^optim_result$par[1:15]
species_params(params_optim)$erepro<-optim_result$par[16:30]
species_params(params_optim)$interaction_resource <-optim_result$par[31:45]
 
sim_optim <- project(params_optim, t_max = 2000)
plotBiomass(sim_optim)
#put these new vals intospecies_params and go back to the top of this page to re-check the calibration 
species_params(params_optim)$R_max
species_params(params_optim)$erepro
species_params(params_optim)$interaction_resource
# this function adds a lower boundary to selected size
plotBiomassObservedVsModelCustom <- function (object, species = NULL, ratio = FALSE, log_scale = TRUE, 
    return_data = FALSE, labels = TRUE, show_unobserved = FALSE) 
{
    if (is(object, "MizerSim")) {
        params = object@params
        n <- finalN(object)
    }
    else if (is(object, "MizerParams")) {
        params = object
        n <- initialN(params)
    }
    else {
        stop("You have not provided a valid mizerSim or mizerParams object.")
    }
    sp_params <- params@species_params
    species = valid_species_arg(object, species)
    if (length(species) == 0) 
        stop("No species selected, please fix.")
    row_select = match(species, sp_params$species)
    if (!"biomass_observed" %in% names(sp_params)) {
        stop("You have not provided values for the column 'biomass_observed' ", 
            "in the mizerParams/mizerSim object.")
    }
    else if (!is.numeric(sp_params$biomass_observed)) {
        stop("The column 'biomass_observed' in the mizerParams/mizerSim object", 
            " is not numeric, please fix.")
    }
    else {
        biomass_observed = sp_params$biomass_observed
    }
    
    cutoffLow <- sp_params$biomass_cutoffLow[row_select]
    if (is.null(cutoffLow)) {
        cutoffLow = rep(0, length(species))
    }
    else if (!is.numeric(cutoffLow)) {
        stop("params@species_params$biomass_cutoffLow is not numeric, \",\n                 \"please fix.")
    }
    cutoffLow[is.na(cutoffLow)] <- 0
    
    cutoffHigh <- sp_params$biomass_cutoffHigh[row_select]
    if (is.null(cutoffHigh)) {
        cutoffHigh = rep(0, length(species))
    }
    else if (!is.numeric(cutoffHigh)) {
        stop("params@species_params$biomass_cutoffHigh is not numeric, \",\n                 \"please fix.")
    }
    cutoffHigh[is.na(cutoffHigh)] <- 0
    
    sim_biomass = rep(0, length(species))
    for (j in 1:length(species)) {
        sim_biomass[j] = sum((n[row_select[j], ] * params@w * 
            params@dw)[params@w >= cutoffLow[j] & cutoffHigh[j] >= params@w])
    }
    dummy = data.frame(species = species, model = sim_biomass, 
        observed = biomass_observed[row_select]) %>% mutate(species = factor(species, 
        levels = species), is_observed = !is.na(observed) & observed > 
        0, observed = case_when(is_observed ~ observed, !is_observed ~ 
        model), ratio = model/observed)
    if (sum(dummy$is_observed) == 0) {
        cat(paste("There are no observed biomasses to compare to model,", 
            "only plotting model biomasses.", sep = "\n"))
    }
    if (!show_unobserved) {
        dummy <- filter(dummy, is_observed)
    }
    if (return_data == TRUE) 
        return(dummy)
    tre <- round(sum(abs(1 - dummy$ratio)), digits = 3)
    caption <- paste0("Total relative error = ", tre)
    if (any(!dummy$is_observed)) {
        caption <- paste(caption, "\n Open circles represent species without biomass observation.")
    }
    if (ratio == FALSE) {
        gg <- ggplot(data = dummy, aes(x = observed, y = model, 
            colour = species, shape = is_observed)) + geom_abline(aes(intercept = 0, 
            slope = 1), colour = "purple", linetype = "dashed", 
            size = 1.3) + geom_point(size = 3) + labs(y = "model biomass [g]") + 
            coord_cartesian(ylim = range(dummy$model, dummy$observed))
    }
    else {
        gg <- ggplot(data = dummy, aes(x = observed, y = ratio, 
            colour = species, shape = is_observed)) + geom_hline(aes(yintercept = 1), 
            linetype = "dashed", colour = "purple", 
            size = 1.3) + geom_point(size = 3) + labs(y = "model biomass / observed biomass") + 
            coord_cartesian(ylim = range(dummy$ratio))
    }
    gg <- gg + labs(x = "observed biomass [g]", caption = caption) + 
        scale_colour_manual(values = getColours(params)[dummy$species]) + 
        scale_shape_manual(values = c(`TRUE` = 19, `FALSE` = 1)) + 
        guides(shape = "none")
    if (log_scale == TRUE & ratio == FALSE) {
        gg = gg + scale_x_log10() + scale_y_log10()
    }
    if (log_scale == TRUE & ratio == TRUE) {
        gg = gg + scale_x_log10()
    }
    if (labels == TRUE) {
        gg = gg + ggrepel::geom_label_repel(aes(label = species), 
            box.padding = 0.35, point.padding = 0.5, segment.color = "grey50", 
            show.legend = FALSE, max.overlaps = Inf, seed = 42)
    }
    gg
}
plotBiomassObservedVsModelCustom(sim_optim)

Use tuneParams() to investigate the species with erepro values too high

params_tuned_v01 <- tuneParams(params_optim)

params_tuned_v01@species_params$erepro

params_tuned_v01 <- steady(params_tuned_v01)
# create set of params for the optimisation process
tic()

params_optim <- params_tuned_v01

vary <- c(log10(params_optim@species_params$R_max),
          params_optim@species_params$erepro,
          params_optim@species_params$interaction_resource)

params_optim<-setParams(params_optim)

# set up workers
noCores <- parallel::detectCores() - 1 # keep some spare core
cl <- parallel::makeCluster(noCores, setup_timeout = 0.5)
setDefaultCluster(cl = cl)
clusterExport(cl, varlist = "cl",envir=environment())
clusterEvalQ(cl, {
  library(mizerExperimental)
  library(optimParallel)
})

optim_result <- optimParallel::optimParallel(par=vary,getErrorCustom,params=params_optim, 
                                             dat = params_optim@species_params$biomass_observed, method ="L-BFGS-B", 
                                             lower=c(rep(-15,15),rep(1e-7,15),rep(.1,15)),
                                             upper= c(rep(15,15),rep(0.99,15),rep(.99,15)),
                                             parallel=list(loginfo=TRUE, forward=TRUE))
stopCluster(cl)

toc()

saveRDS(optim_result, file="optim_result_v01.RDS")
# optim_result <- readRDS("optim_result_v00.RDS")
#put these new vals intospecies_params and go back to the top of this page to re-check the calibration 
species_params(params_optim)$R_max<-10^optim_result$par[1:15]
species_params(params_optim)$erepro<-optim_result$par[16:30]
species_params(params_optim)$interaction_resource <-optim_result$par[31:45]

species_params(params_optim)$R_max
species_params(params_optim)$erepro
species_params(params_optim)$interaction_resource
sim_optim_v02 <- project(params_optim, t_max = 1000)
plotBiomass(sim_optim_v02)
params_v03 <- steady(params_optim)
params_loop <- params_v03 |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady() |>
    matchBiomasses() |> steady() |> matchBiomasses() |> steady()

params_loop@species_params$erepro
sim_v02 <- project(params_loop, t_max = 2000)
plotBiomass(sim_v02)
plotBiomassObservedVsModelCustom(sim_v02)
plotBiomassObservedVsModel(sim_v02)
plotDiet(params_loop)

Save progress

# saveRDS(params_loop, "params_optim_v01.rds")

Try to ween the species of the resource spectra

params_loop@resource_params$w_pp_cutoff
params_loop@resource_params$kappa
resource_params(params_loop)[["w_pp_cutoff"]] <- 10

params_v04 <- setParams(params_loop)

params_v04@resource_params$w_pp_cutoff
sim_v03 <- project(params_v04, t_max = 200)

plotBiomass(sim_v03)
plotBiomassObservedVsModelCustom(sim_v03)
plotBiomassObservedVsModel(sim_v03)
plotDiet(params_v04)
getErrorCustom_v02 <- function(vary, params, dat, tol = 0.001, 
    timetorun = 10)
{
  params@species_params$R_max[1:15]<-10^vary[1:15] # R_max for 15 species
  params@species_params$erepro[1:15]<-vary[16:30] # erepro for 15 species
  params@species_params$interaction_resource[1:15] <- vary[31:45] # interaction_resource for 15 species
  params@resource_params$w_pp_cutoff[1] <- vary[46] # interaction_resource for 15 species
  params <- setParams(params)
  # interaction <- params@interaction
  # interaction[] <- matrix(vary[28:108],nrow = 9) # stop at 54 if looking only at 3 biggest species
  
  # params <- setInteraction(params,interaction)
    params <- projectToSteady(params, distance_func = distanceSSLogN, 
        tol = tol, t_max = 200, return_sim = F)
    
    sim <- project(params, t_max = timetorun, progress_bar = F)
    
    sim_biomass = rep(0, length(params@species_params$species))
    
        cutoffLow <- params@species_params$biomass_cutoffLow
    if (is.null(cutoffLow)) 
        cutoffLow <- rep(0, no_sp)
    cutoffLow[is.na(cutoffLow)] <- 0
    
        cutoffHigh <- params@species_params$biomass_cutoffHigh
    if (is.null(cutoffHigh)) 
        cutoffHigh <- rep(0, no_sp)
    cutoffHigh[is.na(cutoffHigh)] <- 0
        
    for (j in 1:length(sim_biomass)) {
        sim_biomass[j] = sum((sim@n[dim(sim@n)[1],j,] * params@w * 
            params@dw)[params@w >= cutoffLow[j] & cutoffHigh[j] >= params@w])
    }
    
     pred <- log(sim_biomass)
    dat <- log(dat)
    discrep <- pred - dat
    discrep <- (sum(discrep^2))
    return(discrep)
}
    
# create set of params for the optimisation process
tic()

params_optim <- params_v04

vary <- c(log10(params_optim@species_params$R_max),
          params_optim@species_params$erepro,
          params_optim@species_params$interaction_resource,
          params_optim@resource_params$w_pp_cutoff)

params_optim<-setParams(params_optim)

# set up workers
noCores <- parallel::detectCores() - 1 # keep some spare core
cl <- parallel::makeCluster(noCores, setup_timeout = 0.5)
setDefaultCluster(cl = cl)
clusterExport(cl, varlist = "cl",envir=environment())
clusterEvalQ(cl, {
  library(mizerExperimental)
  library(optimParallel)
})

optim_result <- optimParallel::optimParallel(par=vary,getErrorCustom_v02,params=params_optim, 
                                             dat = params_optim@species_params$biomass_observed, method ="L-BFGS-B", 
                                             lower=c(rep(-15,15),rep(1e-7,15),rep(.1,15), 0.1),
                                             upper= c(rep(15,15),rep(0.99,15),rep(.99,15),1000),
                                             parallel=list(loginfo=TRUE, forward=TRUE))
stopCluster(cl)

toc()

saveRDS(optim_result, file="optim_result_v02.RDS")
# optim_result <- readRDS("optim_result_v00.RDS")
#put these new vals intospecies_params and go back to the top of this page to re-check the calibration 
species_params(params_optim)$R_max<-10^optim_result$par[1:15]
species_params(params_optim)$erepro<-optim_result$par[16:30]
species_params(params_optim)$interaction_resource <-optim_result$par[31:45]
resource_params(params_optim)$w_pp_cutoff <- optim_result$par[46]

species_params(params_optim)$R_max
species_params(params_optim)$erepro
species_params(params_optim)$interaction_resource
sim_v04 <- project(params_optim, t_max = 1000)

plotBiomass(sim_v04)
plotBiomassObservedVsModelCustom(sim_v04)
plotBiomassObservedVsModel(sim_v04)
plotDiet(params_optim)
params_steady <- params_optim

initialN(params_steady) <- sim_v04@n[dim(sim_v04@n)[1],,]

plotDiet(params_steady)

sim_v05 <- project(params_steady, t_max = 100)

plotBiomass(sim_v05)

plotGrowthCurves(sim_v05, species_panel = T)
params_tuned_v02 <- tuneParams(params_steady)

params_tuned_v02 <- steady(params_tuned_v02)

params_tuned_v02@species_params$erepro

species w_min w_mat w_max beta k_vb h min_depth max_depth water.column.use p_time_prydz pc_annual_offspring 5 salps 3.162278e-05 0.2511886 25.11886 1000 NA 33 0 500 non DVM 1 NA biomass_observed 5 0.652

species_params <- data.frame(
    species = "salps",
    w_min = 3.162278e-05,
    w_max = 25.11886,
    w_mat = 0.2511886,
    beta = 1000000,
    sigma = 2,
    biomass_observed = 0.652,
    k_vb = 0.4,
    yield_observed = 0,
    biomass_cutoff = 0.1,
    biomass_cutoffLow = 0.1,
    biomass_cutoffHigh = 25.11886
)

params_v05 <- addSpecies(params_tuned_v02, species_params)
plotSpectra(params_v05)

params_v05@species_params$erepro
# function running tuneParams function in a row for a quick start to a calibration
fastCalib <- function(params, match = F)
{
params <- calibrateBiomass(params) # changes kappa and rmax
if(match) params <- matchBiomasses(params) # set rmax to inf and adjust erepro
params <- steady(params, tol = 0.001)
sim <- project(params, t_max = 1000)
return(sim)
}
sim_v06 <- fastCalib(params_v05)

plotBiomass(sim_v06)
plotDiet(params_v05)
so_theta <- as.matrix(params_v05@interaction)

salp_row <- c(1,
0.1250000,
0.1250000,
0.1373626,
0.0500000,
0.1000000,
0.2500000,
0.2500000,
0.1000000,
0.1666667,
0.1666667,
0.0500000,
0.2000000,
0.1250000,
0.2000000,
1)
so_theta[16,] # automated salps interaction when added using addSpecies()

so_theta[16,] <- salp_row

so_theta[,16] # automated salps interaction when added using addSpecies()

so_theta[,16] <- salp_row

so_theta
params_v06 <- setParams(params_v05, interaction = so_theta)

params_v06@interaction
sim_v07 <- fastCalib(params_v06)

plotBiomass(sim_v07)
initialN(params_v06) <- sim_v07@n[dim(sim_v07@n)[1],,]
sim_v08 <- project(params_v06, t_max = 100)
plotBiomass(sim_v08)
plotDiet(params_v06)

Fill in missing and adjust beta values for zooplankton groups using Heneghan et al. 2020 (10.1016/j.ecolmodel.2020.109265)

Need a value for microzooplankton microzooplankton (in McCormack et al. 2020) is composed of Heterotrophic dinoflagellates, tintinnids, ciliates, copepod nauplii Heneghan et al. log10PPMR values for: Hetero.Flagellates = 0.2–0.72 -> 0.46 Hetero.Ciliates = 2.5–2.9 -> 2.7 Mean: (2.7+0.46)/2 = 1.58 10^1.58 = 38.01894

Need to adjust values for mesozoo, other macrozoo, euphausiids, salps

Heneghan et al. log10PPMR values (midpoints for range) for: salps = 6.8–11.7 -> 9.25 10^9.25 = 1778279410

euphausiids = 6.6–7.8 -> 7.2 10^7.2 = 15848932

mesozoo (copepods) Omni.Cop. = 3.6–4.6 -> 4.1 Carn.Cop. = 0.8–1.9 -> 1.35 Mean: (4.1+1.35)/2 = 2.725 10^2.725 = 530.8844

other macrozoo () Chaetognaths = 1.9–3.4 -> 2.65 10^2.65 = 446.6836

params_tuned_v03 <- tuneParams(params_v06)
params_tuned_v04 <- tuneParams(params_tuned_v03) # updated salps PPMR to match empirical estimates from Heneghan et al 2020
getErrorCustom_v3 <- function(vary, params, dat, tol = 0.001, 
    timetorun = 10)
{
  params@species_params$R_max[1:16]<-10^vary[1:16] # R_max for 15 species
  params@species_params$erepro[1:16]<-vary[17:32] # erepro for 15 species
  params@species_params$interaction_resource[1:16] <- vary[33:48] # interaction_resource for 15 species
  params <- setParams(params)
  # interaction <- params@interaction
  # interaction[] <- matrix(vary[28:108],nrow = 9) # stop at 54 if looking only at 3 biggest species
  
  # params <- setInteraction(params,interaction)
    params <- projectToSteady(params, distance_func = distanceSSLogN, 
        tol = tol, t_max = 200, return_sim = F)
    
    sim <- project(params, t_max = timetorun, progress_bar = F)
    
    sim_biomass = rep(0, length(params@species_params$species))
    
        cutoffLow <- params@species_params$biomass_cutoffLow
    if (is.null(cutoffLow)) 
        cutoffLow <- rep(0, no_sp)
    cutoffLow[is.na(cutoffLow)] <- 0
    
        cutoffHigh <- params@species_params$biomass_cutoffHigh
    if (is.null(cutoffHigh)) 
        cutoffHigh <- rep(0, no_sp)
    cutoffHigh[is.na(cutoffHigh)] <- 0
        
    for (j in 1:length(sim_biomass)) {
        sim_biomass[j] = sum((sim@n[dim(sim@n)[1],j,] * params@w * 
            params@dw)[params@w >= cutoffLow[j] & cutoffHigh[j] >= params@w])
    }
    
     pred <- log(sim_biomass)
    dat <- log(dat)
    discrep <- pred - dat
    discrep <- (sum(discrep^2))
    return(discrep)
}
# create set of params for the optimisation process
tic()

params_optim <- params_tuned_v04

vary <- c(log10(params_optim@species_params$R_max),
          params_optim@species_params$erepro,
          params_optim@species_params$interaction_resource)

params_optim<-setParams(params_optim)

# set up workers
noCores <- parallel::detectCores() - 1 # keep some spare core
cl <- parallel::makeCluster(noCores, setup_timeout = 0.5)
setDefaultCluster(cl = cl)
clusterExport(cl, varlist = "cl",envir=environment())
clusterEvalQ(cl, {
  library(mizerExperimental)
  library(optimParallel)
})

optim_result <- optimParallel::optimParallel(par=vary,getErrorCustom_v3,params=params_optim, 
                                             dat = params_optim@species_params$biomass_observed, method ="L-BFGS-B", 
                                             lower=c(rep(-15,16),rep(1e-7,16),rep(.1,16)),
                                             upper= c(rep(15,16),rep(0.99,16),rep(.99,16)),
                                             parallel=list(loginfo=TRUE, forward=TRUE))
stopCluster(cl)

toc()

saveRDS(optim_result, file="optim_result_v03.RDS")
# optim_result <- readRDS("optim_result_v00.RDS")
#put these new vals intospecies_params and go back to the top of this page to re-check the calibration 
species_params(params_optim)$R_max<-10^optim_result$par[1:16]
species_params(params_optim)$erepro<-optim_result$par[17:32]
species_params(params_optim)$interaction_resource <-optim_result$par[33:48]

species_params(params_optim)$R_max
species_params(params_optim)$erepro
species_params(params_optim)$interaction_resource
sim_v09 <- project(params_optim, t_max = 200)
plotBiomass(sim_v09)
params_v07 <- params_optim
initialN(params_v07) <- sim_v09@n[dim(sim_v09@n)[1],,]
sim_v10 <- project(params_v07, t_max = 200)
plotBiomass(sim_v10)
plotDiet(params_v07)
initialN(params_v07) <- sim_v10@n[dim(sim_v10@n)[1],,]
sim_v11 <- project(params_v07, t_max = 200)
plotBiomass(sim_v11)
params_tuned_v05 <- tuneParams(params_v07)

params_tuned_v05 <- steady(params_tuned_v05)

params_tuned_v05@species_params$erepro
# saveRDS(params_tuned_v05, "params_optim_v02.rds")

params_tuned_v05 <- readRDS("params_optim_v02.rds")
sim_v12 <- project(params_tuned_v05, t_max = 500)

initialN(params_tuned_v05) <- sim_v12@n[dim(sim_v12@n)[1],,]

sim_v13 <- project(params_tuned_v05, t_max = 500)
plotlyBiomass(sim_v13)
plotBiomassObservedVsModel(sim_v13)
plotBiomassObservedVsModelCustom(sim_v13)

Gradually reducing resource maximum size in tuneParams(), as doing it directly in the setParams() route will tell you the w_pp_cutoff has changed, but it will still incorporate a background resource up to the w_pp_cutoff that was originally used in newMultispeciesParams()

params_tuned_v06 <- tuneParams(params_tuned_v05)

params_tuned_v06 <- steady(params_tuned_v06)

params_tuned_v06@species_params$erepro
params_tuned_v06@species_params$R_max
params_tuned_v10 <- tuneParams(params_tuned_v06)

params_tuned_v10 <- steady(params_tuned_v10)

params_tuned_v10@species_params$erepro
params_tuned_v10@species_params$R_max

params_tuned_v10@resource_params$w_pp_cutoff
# saveRDS(params_tuned_v06, "params_optim_v02_w_pp_100.rds")
# saveRDS(params_tuned_v10, "params_optim_v03_w_pp_100.rds")
# create set of params for the optimisation process
tic()

params_optim <- params_tuned_v10

vary <- c(log10(params_optim@species_params$R_max),
          params_optim@species_params$erepro,
          params_optim@species_params$interaction_resource)

params_optim<-setParams(params_optim)

# set up workers
noCores <- parallel::detectCores() - 1 # keep some spare core
cl <- parallel::makeCluster(noCores, setup_timeout = 0.5)
setDefaultCluster(cl = cl)
clusterExport(cl, varlist = "cl",envir=environment())
clusterEvalQ(cl, {
  library(mizerExperimental)
  library(optimParallel)
})

optim_result <- optimParallel::optimParallel(par=vary,getErrorCustom_v3,params=params_optim,
                                             dat = params_optim@species_params$biomass_observed, method ="L-BFGS-B",
                                             lower=c(rep(-15,16),rep(1e-7,16),rep(.1,16)),
                                             upper= c(rep(15,16),rep(0.99,16),rep(.99,16)),
                                             parallel=list(loginfo=TRUE, forward=TRUE))
stopCluster(cl)

toc()

saveRDS(optim_result, file="optim_result_v04.RDS")

# optim_result <- readRDS("optim_result_v04.RDS")
#put these new vals intospecies_params and go back to the top of this page to re-check the calibration 
species_params(params_optim)$R_max<-10^optim_result$par[1:16]
species_params(params_optim)$erepro<-optim_result$par[17:32]
species_params(params_optim)$interaction_resource <-optim_result$par[33:48]

species_params(params_optim)$R_max
species_params(params_optim)$erepro
species_params(params_optim)$interaction_resource
sim_v14 <- project(params_optim, t_max = 2000)
plotBiomass(sim_v14)
params_v08 <- params_optim
initialN(params_v08) <- sim_v14@n[dim(sim_v14@n)[1],,]
# saveRDS(params_tuned_v07, file="params_optim_v04_w_pp_100.rds")
params_tuned_v07 <- readRDS("params_optim_v04_w_pp_100.rds")
Warning: cannot open compressed file 'params_optim_v04_w_pp_100.rds', probable reason 'No such file or directory'Error in gzfile(file, "rb") : cannot open the connection
sim_v15 <- project(params_tuned_v07, t_max = 2000)

[--------------------------------------------]   0% ETA:  1m
[--------------------------------------------]   0% ETA:  2m
[--------------------------------------------]   0% ETA:  1m
[--------------------------------------------]   0% ETA:  2m
[--------------------------------------------]   1% ETA:  2m
[--------------------------------------------]   1% ETA:  1m
[--------------------------------------------]   1% ETA:  2m
[>-------------------------------------------]   1% ETA:  2m
[>-------------------------------------------]   1% ETA:  1m
[>-------------------------------------------]   1% ETA:  2m
[>-------------------------------------------]   2% ETA:  2m
[>-------------------------------------------]   2% ETA:  1m
[>-------------------------------------------]   2% ETA:  2m
[>-------------------------------------------]   2% ETA:  1m
[>-------------------------------------------]   2% ETA:  2m
[>-------------------------------------------]   2% ETA:  1m
[>-------------------------------------------]   2% ETA:  2m
[>-------------------------------------------]   2% ETA:  1m
[>-------------------------------------------]   3% ETA:  2m
[>-------------------------------------------]   3% ETA:  1m
[>-------------------------------------------]   3% ETA:  2m
[>-------------------------------------------]   3% ETA:  1m
[>-------------------------------------------]   3% ETA:  2m
[>-------------------------------------------]   3% ETA:  1m
[>-------------------------------------------]   3% ETA:  2m
[>-------------------------------------------]   3% ETA:  1m
[>-------------------------------------------]   3% ETA:  2m
[>-------------------------------------------]   3% ETA:  1m
[=>------------------------------------------]   3% ETA:  1m
[=>------------------------------------------]   3% ETA:  2m
[=>------------------------------------------]   4% ETA:  1m
[=>------------------------------------------]   5% ETA:  1m
[=>------------------------------------------]   6% ETA:  1m
[==>-----------------------------------------]   6% ETA:  1m
[==>-----------------------------------------]   7% ETA:  1m
[==>-----------------------------------------]   8% ETA:  1m
[===>----------------------------------------]   8% ETA:  1m
[===>----------------------------------------]   9% ETA:  1m
[===>----------------------------------------]  10% ETA:  1m
[====>---------------------------------------]  10% ETA:  1m
[====>---------------------------------------]  11% ETA:  1m
[====>---------------------------------------]  12% ETA:  1m
[=====>--------------------------------------]  13% ETA:  1m
[=====>--------------------------------------]  14% ETA:  1m
[=====>--------------------------------------]  15% ETA:  1m
[======>-------------------------------------]  15% ETA:  1m
[======>-------------------------------------]  16% ETA:  1m
[======>-------------------------------------]  17% ETA:  1m
[=======>------------------------------------]  17% ETA:  1m
[=======>------------------------------------]  18% ETA:  1m
[=======>------------------------------------]  19% ETA:  1m
[========>-----------------------------------]  19% ETA:  1m
[========>-----------------------------------]  20% ETA:  1m
[========>-----------------------------------]  21% ETA:  1m
[========>-----------------------------------]  22% ETA:  1m
[=========>----------------------------------]  22% ETA:  1m
[=========>----------------------------------]  23% ETA:  1m
[=========>----------------------------------]  24% ETA:  1m
[==========>---------------------------------]  24% ETA:  1m
[==========>---------------------------------]  25% ETA:  1m
[==========>---------------------------------]  26% ETA:  1m
[===========>--------------------------------]  26% ETA:  1m
[===========>--------------------------------]  27% ETA:  1m
[===========>--------------------------------]  28% ETA:  1m
[============>-------------------------------]  28% ETA:  1m
[============>-------------------------------]  29% ETA:  1m
[============>-------------------------------]  30% ETA:  1m
[============>-------------------------------]  31% ETA:  1m
[=============>------------------------------]  31% ETA:  1m
[=============>------------------------------]  32% ETA:  1m
[=============>------------------------------]  33% ETA:  1m
[==============>-----------------------------]  33% ETA:  1m
[==============>-----------------------------]  34% ETA:  1m
[==============>-----------------------------]  35% ETA:  1m
[===============>----------------------------]  35% ETA:  1m
[===============>----------------------------]  36% ETA:  1m
[===============>----------------------------]  37% ETA:  1m
[================>---------------------------]  38% ETA:  1m
[================>---------------------------]  39% ETA:  1m
[================>---------------------------]  40% ETA:  1m
[=================>--------------------------]  40% ETA:  1m
[=================>--------------------------]  41% ETA:  1m
[=================>--------------------------]  42% ETA:  1m
[==================>-------------------------]  42% ETA:  1m
[==================>-------------------------]  42% ETA: 50s
[==================>-------------------------]  43% ETA: 50s
[==================>-------------------------]  43% ETA: 49s
[==================>-------------------------]  43% ETA: 50s
[==================>-------------------------]  43% ETA: 49s
[==================>-------------------------]  44% ETA: 49s
[==================>-------------------------]  44% ETA: 48s
[==================>-------------------------]  44% ETA: 49s
[==================>-------------------------]  44% ETA: 48s
[===================>------------------------]  44% ETA: 48s
[===================>------------------------]  45% ETA: 48s
[===================>------------------------]  45% ETA: 47s
[===================>------------------------]  46% ETA: 47s
[===================>------------------------]  46% ETA: 46s
[===================>------------------------]  47% ETA: 46s
[====================>-----------------------]  47% ETA: 46s
[====================>-----------------------]  47% ETA: 45s
[====================>-----------------------]  48% ETA: 45s
[====================>-----------------------]  48% ETA: 44s
[====================>-----------------------]  49% ETA: 44s
[=====================>----------------------]  49% ETA: 44s
[=====================>----------------------]  49% ETA: 43s
[=====================>----------------------]  50% ETA: 44s
[=====================>----------------------]  50% ETA: 43s
[=====================>----------------------]  51% ETA: 43s
[=====================>----------------------]  51% ETA: 42s
[======================>---------------------]  51% ETA: 42s
[======================>---------------------]  52% ETA: 42s
[======================>---------------------]  52% ETA: 41s
[======================>---------------------]  53% ETA: 41s
[======================>---------------------]  53% ETA: 40s
[======================>---------------------]  53% ETA: 41s
[======================>---------------------]  53% ETA: 40s
[=======================>--------------------]  53% ETA: 40s
[=======================>--------------------]  54% ETA: 40s
[=======================>--------------------]  54% ETA: 39s
[=======================>--------------------]  55% ETA: 39s
[=======================>--------------------]  55% ETA: 38s
[=======================>--------------------]  56% ETA: 38s
[========================>-------------------]  56% ETA: 38s
[========================>-------------------]  56% ETA: 37s
[========================>-------------------]  56% ETA: 38s
[========================>-------------------]  56% ETA: 37s
[========================>-------------------]  57% ETA: 37s
[========================>-------------------]  57% ETA: 36s
[========================>-------------------]  58% ETA: 36s
[=========================>------------------]  58% ETA: 36s
[=========================>------------------]  59% ETA: 36s
[=========================>------------------]  59% ETA: 35s
[=========================>------------------]  60% ETA: 35s
[=========================>------------------]  60% ETA: 34s
[==========================>-----------------]  60% ETA: 34s
[==========================>-----------------]  61% ETA: 34s
[==========================>-----------------]  61% ETA: 33s
[==========================>-----------------]  62% ETA: 33s
[==========================>-----------------]  62% ETA: 32s
[===========================>----------------]  63% ETA: 32s
[===========================>----------------]  63% ETA: 31s
[===========================>----------------]  64% ETA: 31s
[===========================>----------------]  64% ETA: 30s
[===========================>----------------]  65% ETA: 30s
[============================>---------------]  65% ETA: 30s
[============================>---------------]  65% ETA: 29s
[============================>---------------]  66% ETA: 29s
[============================>---------------]  67% ETA: 29s
[============================>---------------]  67% ETA: 28s
[=============================>--------------]  67% ETA: 28s
[=============================>--------------]  68% ETA: 28s
[=============================>--------------]  68% ETA: 27s
[=============================>--------------]  69% ETA: 27s
[=============================>--------------]  69% ETA: 26s
[==============================>-------------]  69% ETA: 26s
[==============================>-------------]  70% ETA: 26s
[==============================>-------------]  70% ETA: 25s
[==============================>-------------]  71% ETA: 25s
[==============================>-------------]  71% ETA: 24s
[==============================>-------------]  72% ETA: 24s
[===============================>------------]  72% ETA: 24s
[===============================>------------]  72% ETA: 23s
[===============================>------------]  73% ETA: 23s
[===============================>------------]  74% ETA: 23s
[===============================>------------]  74% ETA: 22s
[================================>-----------]  74% ETA: 22s
[================================>-----------]  75% ETA: 22s
[================================>-----------]  75% ETA: 21s
[================================>-----------]  76% ETA: 21s
[================================>-----------]  76% ETA: 20s
[=================================>----------]  76% ETA: 20s
[=================================>----------]  77% ETA: 20s
[=================================>----------]  77% ETA: 19s
[=================================>----------]  78% ETA: 19s
[=================================>----------]  78% ETA: 18s
[==================================>---------]  78% ETA: 18s
[==================================>---------]  79% ETA: 18s
[==================================>---------]  79% ETA: 17s
[==================================>---------]  80% ETA: 17s
[==================================>---------]  81% ETA: 17s
[==================================>---------]  81% ETA: 16s
[===================================>--------]  81% ETA: 16s
[===================================>--------]  82% ETA: 16s
[===================================>--------]  82% ETA: 15s
[===================================>--------]  83% ETA: 15s
[====================================>-------]  83% ETA: 15s
[====================================>-------]  83% ETA: 14s
[====================================>-------]  84% ETA: 14s
[====================================>-------]  84% ETA: 13s
[====================================>-------]  85% ETA: 13s
[=====================================>------]  85% ETA: 13s
[=====================================>------]  85% ETA: 12s
[=====================================>------]  86% ETA: 12s
[=====================================>------]  87% ETA: 12s
[=====================================>------]  87% ETA: 11s
[======================================>-----]  88% ETA: 11s
[======================================>-----]  88% ETA: 10s
[======================================>-----]  89% ETA: 10s
[======================================>-----]  89% ETA:  9s
[======================================>-----]  90% ETA:  9s
[=======================================>----]  90% ETA:  9s
[=======================================>----]  90% ETA:  8s
[=======================================>----]  91% ETA:  8s
[=======================================>----]  91% ETA:  7s
[=======================================>----]  92% ETA:  7s
[========================================>---]  92% ETA:  7s
[========================================>---]  92% ETA:  6s
[========================================>---]  93% ETA:  6s
[========================================>---]  94% ETA:  6s
[========================================>---]  94% ETA:  5s
[=========================================>--]  94% ETA:  5s
[=========================================>--]  95% ETA:  5s
[=========================================>--]  95% ETA:  4s
[=========================================>--]  96% ETA:  4s
[=========================================>--]  96% ETA:  3s
[=========================================>--]  97% ETA:  3s
[==========================================>-]  97% ETA:  3s
[==========================================>-]  97% ETA:  2s
[==========================================>-]  98% ETA:  2s
[==========================================>-]  98% ETA:  1s
[==========================================>-]  99% ETA:  1s
[===========================================>]  99% ETA:  1s
[===========================================>]  99% ETA:  0s
[===========================================>] 100% ETA:  0s
plotBiomass(sim_v15)

plotDiet(params_tuned_v07)

initialN(params_tuned_v07) <- sim_v15@n[dim(sim_v15@n)[1],,]

sim_v16 <- project(params_tuned_v07, t_max = 500)

[>-------------------------------------------]   3% ETA:  7s
[=>------------------------------------------]   4% ETA:  7s
[=>------------------------------------------]   4% ETA: 11s
[=>------------------------------------------]   5% ETA: 10s
[=>------------------------------------------]   6% ETA: 10s
[==>-----------------------------------------]   6% ETA: 10s
[==>-----------------------------------------]   6% ETA:  9s
[==>-----------------------------------------]   6% ETA: 10s
[==>-----------------------------------------]   7% ETA:  9s
[==>-----------------------------------------]   8% ETA:  9s
[===>----------------------------------------]   8% ETA:  9s
[===>----------------------------------------]   9% ETA:  9s
[===>----------------------------------------]   9% ETA:  8s
[===>----------------------------------------]  10% ETA:  8s
[====>---------------------------------------]  10% ETA:  8s
[====>---------------------------------------]  11% ETA:  8s
[====>---------------------------------------]  12% ETA:  8s
[=====>--------------------------------------]  13% ETA:  8s
[=====>--------------------------------------]  13% ETA:  7s
[=====>--------------------------------------]  14% ETA:  7s
[=====>--------------------------------------]  15% ETA:  7s
[======>-------------------------------------]  15% ETA:  7s
[======>-------------------------------------]  16% ETA:  7s
[======>-------------------------------------]  17% ETA:  7s
[=======>------------------------------------]  17% ETA:  7s
[=======>------------------------------------]  18% ETA:  7s
[=======>------------------------------------]  19% ETA:  7s
[========>-----------------------------------]  19% ETA:  7s
[========>-----------------------------------]  20% ETA:  6s
[========>-----------------------------------]  21% ETA:  6s
[========>-----------------------------------]  22% ETA:  6s
[=========>----------------------------------]  22% ETA:  6s
[=========>----------------------------------]  23% ETA:  6s
[=========>----------------------------------]  24% ETA:  6s
[==========>---------------------------------]  24% ETA:  6s
[==========>---------------------------------]  25% ETA:  6s
[==========>---------------------------------]  26% ETA:  6s
[===========>--------------------------------]  26% ETA:  6s
[===========>--------------------------------]  27% ETA:  6s
[===========>--------------------------------]  28% ETA:  6s
[============>-------------------------------]  29% ETA:  5s
[============>-------------------------------]  30% ETA:  5s
[============>-------------------------------]  31% ETA:  5s
[=============>------------------------------]  31% ETA:  5s
[=============>------------------------------]  32% ETA:  5s
[=============>------------------------------]  33% ETA:  5s
[==============>-----------------------------]  33% ETA:  5s
[==============>-----------------------------]  34% ETA:  5s
[==============>-----------------------------]  35% ETA:  5s
[===============>----------------------------]  35% ETA:  5s
[===============>----------------------------]  36% ETA:  5s
[===============>----------------------------]  37% ETA:  5s
[================>---------------------------]  38% ETA:  5s
[================>---------------------------]  39% ETA:  4s
[================>---------------------------]  40% ETA:  4s
[=================>--------------------------]  40% ETA:  4s
[=================>--------------------------]  41% ETA:  4s
[=================>--------------------------]  42% ETA:  4s
[==================>-------------------------]  42% ETA:  4s
[==================>-------------------------]  43% ETA:  4s
[==================>-------------------------]  44% ETA:  4s
[===================>------------------------]  45% ETA:  4s
[===================>------------------------]  46% ETA:  4s
[===================>------------------------]  47% ETA:  4s
[====================>-----------------------]  47% ETA:  4s
[====================>-----------------------]  48% ETA:  4s
[====================>-----------------------]  49% ETA:  4s
[=====================>----------------------]  49% ETA:  4s
[=====================>----------------------]  50% ETA:  4s
[=====================>----------------------]  51% ETA:  4s
[======================>---------------------]  51% ETA:  4s
[======================>---------------------]  52% ETA:  4s
[======================>---------------------]  52% ETA:  3s
[======================>---------------------]  53% ETA:  3s
[=======================>--------------------]  53% ETA:  3s
[=======================>--------------------]  54% ETA:  3s
[=======================>--------------------]  55% ETA:  3s
[========================>-------------------]  56% ETA:  3s
[========================>-------------------]  57% ETA:  3s
[========================>-------------------]  58% ETA:  3s
[=========================>------------------]  58% ETA:  3s
[=========================>------------------]  59% ETA:  3s
[=========================>------------------]  60% ETA:  3s
[==========================>-----------------]  60% ETA:  3s
[==========================>-----------------]  61% ETA:  3s
[==========================>-----------------]  62% ETA:  3s
[===========================>----------------]  63% ETA:  3s
[===========================>----------------]  64% ETA:  3s
[===========================>----------------]  65% ETA:  2s
[============================>---------------]  65% ETA:  2s
[============================>---------------]  66% ETA:  2s
[============================>---------------]  67% ETA:  2s
[=============================>--------------]  67% ETA:  2s
[=============================>--------------]  68% ETA:  2s
[=============================>--------------]  69% ETA:  2s
[==============================>-------------]  69% ETA:  2s
[==============================>-------------]  70% ETA:  2s
[==============================>-------------]  71% ETA:  2s
[===============================>------------]  72% ETA:  2s
[===============================>------------]  73% ETA:  2s
[===============================>------------]  74% ETA:  2s
[================================>-----------]  74% ETA:  2s
[================================>-----------]  75% ETA:  2s
[================================>-----------]  76% ETA:  2s
[=================================>----------]  76% ETA:  2s
[=================================>----------]  77% ETA:  2s
[=================================>----------]  78% ETA:  2s
[=================================>----------]  78% ETA:  1s
[==================================>---------]  78% ETA:  1s
[==================================>---------]  79% ETA:  1s
[==================================>---------]  80% ETA:  1s
[==================================>---------]  81% ETA:  1s
[===================================>--------]  81% ETA:  1s
[===================================>--------]  82% ETA:  1s
[===================================>--------]  83% ETA:  1s
[====================================>-------]  83% ETA:  1s
[====================================>-------]  84% ETA:  1s
[====================================>-------]  85% ETA:  1s
[=====================================>------]  85% ETA:  1s
[=====================================>------]  86% ETA:  1s
[=====================================>------]  87% ETA:  1s
[======================================>-----]  88% ETA:  1s
[======================================>-----]  89% ETA:  1s
[======================================>-----]  90% ETA:  1s
[=======================================>----]  90% ETA:  1s
[=======================================>----]  91% ETA:  1s
[=======================================>----]  92% ETA:  1s
[========================================>---]  92% ETA:  1s
[========================================>---]  93% ETA:  1s
[========================================>---]  93% ETA:  0s
[========================================>---]  94% ETA:  0s
[=========================================>--]  94% ETA:  0s
[=========================================>--]  95% ETA:  0s
[=========================================>--]  96% ETA:  0s
[==========================================>-]  97% ETA:  0s
[==========================================>-]  98% ETA:  0s
[==========================================>-]  99% ETA:  0s
[===========================================>]  99% ETA:  0s
[===========================================>] 100% ETA:  0s
plotlyBiomass(sim_v16)
plotBiomassObservedVsModel(sim_v16)

plotlyBiomass(params_loop)
Error: is(object = sim, class2 = "MizerSim") is not TRUE
sim_v17 <- project(params_loop, t_max = 500)

[>-------------------------------------------]   3% ETA:  6s
[=>------------------------------------------]   4% ETA:  6s
[=>------------------------------------------]   4% ETA:  9s
[=>------------------------------------------]   5% ETA:  9s
[=>------------------------------------------]   6% ETA:  9s
[==>-----------------------------------------]   6% ETA:  8s
[==>-----------------------------------------]   7% ETA:  8s
[==>-----------------------------------------]   7% ETA: 10s
[==>-----------------------------------------]   7% ETA:  9s
[==>-----------------------------------------]   8% ETA:  9s
[===>----------------------------------------]   8% ETA:  9s
[===>----------------------------------------]   9% ETA:  9s
[===>----------------------------------------]  10% ETA:  9s
[===>----------------------------------------]  10% ETA:  8s
[====>---------------------------------------]  10% ETA:  8s
[====>---------------------------------------]  11% ETA:  8s
[====>---------------------------------------]  12% ETA:  8s
[=====>--------------------------------------]  13% ETA:  8s
[=====>--------------------------------------]  14% ETA:  8s
[=====>--------------------------------------]  14% ETA:  7s
[=====>--------------------------------------]  15% ETA:  7s
[======>-------------------------------------]  15% ETA:  7s
[======>-------------------------------------]  16% ETA:  7s
[======>-------------------------------------]  17% ETA:  7s
[=======>------------------------------------]  17% ETA:  7s
[=======>------------------------------------]  18% ETA:  7s
[=======>------------------------------------]  19% ETA:  7s
[========>-----------------------------------]  19% ETA:  7s
[========>-----------------------------------]  20% ETA:  7s
[========>-----------------------------------]  20% ETA:  6s
[========>-----------------------------------]  21% ETA:  6s
[========>-----------------------------------]  22% ETA:  6s
[=========>----------------------------------]  22% ETA:  6s
[=========>----------------------------------]  23% ETA:  6s
[=========>----------------------------------]  24% ETA:  6s
[==========>---------------------------------]  24% ETA:  6s
[==========>---------------------------------]  25% ETA:  6s
[==========>---------------------------------]  26% ETA:  6s
[===========>--------------------------------]  26% ETA:  6s
[===========>--------------------------------]  27% ETA:  6s
[===========>--------------------------------]  28% ETA:  6s
[============>-------------------------------]  29% ETA:  6s
[============>-------------------------------]  29% ETA:  5s
[============>-------------------------------]  30% ETA:  5s
[============>-------------------------------]  31% ETA:  5s
[=============>------------------------------]  31% ETA:  5s
[=============>------------------------------]  32% ETA:  5s
[=============>------------------------------]  33% ETA:  5s
[==============>-----------------------------]  33% ETA:  5s
[==============>-----------------------------]  34% ETA:  5s
[==============>-----------------------------]  35% ETA:  5s
[===============>----------------------------]  35% ETA:  5s
[===============>----------------------------]  36% ETA:  5s
[===============>----------------------------]  37% ETA:  5s
[================>---------------------------]  38% ETA:  5s
[================>---------------------------]  39% ETA:  5s
[================>---------------------------]  40% ETA:  5s
[=================>--------------------------]  40% ETA:  5s
[=================>--------------------------]  41% ETA:  5s
[=================>--------------------------]  42% ETA:  5s
[==================>-------------------------]  42% ETA:  5s
[==================>-------------------------]  43% ETA:  5s
[==================>-------------------------]  43% ETA:  4s
[==================>-------------------------]  44% ETA:  4s
[===================>------------------------]  45% ETA:  4s
[===================>------------------------]  46% ETA:  4s
[===================>------------------------]  47% ETA:  4s
[====================>-----------------------]  47% ETA:  4s
[====================>-----------------------]  48% ETA:  4s
[====================>-----------------------]  49% ETA:  4s
[=====================>----------------------]  49% ETA:  4s
[=====================>----------------------]  50% ETA:  4s
[=====================>----------------------]  51% ETA:  4s
[======================>---------------------]  51% ETA:  4s
[======================>---------------------]  52% ETA:  4s
[======================>---------------------]  53% ETA:  4s
[=======================>--------------------]  53% ETA:  4s
[=======================>--------------------]  54% ETA:  4s
[=======================>--------------------]  55% ETA:  4s
[========================>-------------------]  56% ETA:  4s
[========================>-------------------]  57% ETA:  4s
[========================>-------------------]  57% ETA:  3s
[========================>-------------------]  58% ETA:  3s
[=========================>------------------]  58% ETA:  3s
[=========================>------------------]  59% ETA:  3s
[=========================>------------------]  60% ETA:  3s
[==========================>-----------------]  60% ETA:  3s
[==========================>-----------------]  61% ETA:  3s
[==========================>-----------------]  62% ETA:  3s
[===========================>----------------]  63% ETA:  3s
[===========================>----------------]  64% ETA:  3s
[===========================>----------------]  65% ETA:  3s
[============================>---------------]  65% ETA:  3s
[============================>---------------]  66% ETA:  3s
[============================>---------------]  67% ETA:  3s
[=============================>--------------]  67% ETA:  3s
[=============================>--------------]  68% ETA:  3s
[=============================>--------------]  69% ETA:  3s
[==============================>-------------]  69% ETA:  3s
[==============================>-------------]  70% ETA:  2s
[==============================>-------------]  71% ETA:  2s
[===============================>------------]  72% ETA:  2s
[===============================>------------]  73% ETA:  2s
[===============================>------------]  74% ETA:  2s
[================================>-----------]  74% ETA:  2s
[================================>-----------]  75% ETA:  2s
[================================>-----------]  76% ETA:  2s
[=================================>----------]  76% ETA:  2s
[=================================>----------]  77% ETA:  2s
[=================================>----------]  78% ETA:  2s
[==================================>---------]  78% ETA:  2s
[==================================>---------]  79% ETA:  2s
[==================================>---------]  80% ETA:  2s
[==================================>---------]  81% ETA:  2s
[===================================>--------]  81% ETA:  2s
[===================================>--------]  81% ETA:  1s
[===================================>--------]  82% ETA:  1s
[===================================>--------]  83% ETA:  1s
[====================================>-------]  83% ETA:  1s
[====================================>-------]  84% ETA:  1s
[====================================>-------]  85% ETA:  1s
[=====================================>------]  85% ETA:  1s
[=====================================>------]  86% ETA:  1s
[=====================================>------]  87% ETA:  1s
[======================================>-----]  88% ETA:  1s
[======================================>-----]  89% ETA:  1s
[======================================>-----]  90% ETA:  1s
[=======================================>----]  90% ETA:  1s
[=======================================>----]  91% ETA:  1s
[=======================================>----]  92% ETA:  1s
[========================================>---]  92% ETA:  1s
[========================================>---]  93% ETA:  1s
[========================================>---]  94% ETA:  1s
[========================================>---]  94% ETA:  0s
[=========================================>--]  94% ETA:  0s
[=========================================>--]  95% ETA:  0s
[=========================================>--]  96% ETA:  0s
[==========================================>-]  97% ETA:  0s
[==========================================>-]  98% ETA:  0s
[==========================================>-]  99% ETA:  0s
[===========================================>]  99% ETA:  0s
[===========================================>] 100% ETA:  0s
plotlyBiomass(sim_v17)
plotBiomassObservedVsModel(sim_v17)

plotBiomassObservedVsModelCustom(sim_v17)
Error in plotBiomassObservedVsModelCustom(sim_v17) : 
  could not find function "plotBiomassObservedVsModelCustom"
params_loop <- steady(params_loop)
Convergence was achieved in 1.5 years.

Reduce interaction with resource gradually to see if that can increase predation on euphausiids

box.params <- params_loop

box.params@species_params$ppmr_min[box.params@species_params$species == "baleen whales"]  <- 4e6
box.params@species_params$ppmr_max[box.params@species_params$species == "baleen whales"] <-5e6
# box.params@species_params$pred_kernel_type[box.params@species_params$species == "baleen whales"] <- "box"
params_v15 <- tuneParams(box.params)

Listening on http://127.0.0.1:7954
NA
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpTdGVwIDE6IHJldmlzZWQgY2F0Y2ggZm9yIDIwMTAtMjAyMA0KU3RlcCAyOiB0dW5lIHJlc2lsaWVuY2Ugb2YgYWxsIHRoZSBzcGVjaWVzIChpLmUuLCBsb25nLWxpdmVkLCBzbG93ZXIgZ3Jvd2luZyBzcGVjaWVzID0gdnVsbmVyYWJsZS4uLmV0Yy4uLikNClN0ZXAgMzogY2FsaWJyYXRlZCBtb2RlbCB3aXRoIGZpc2hpbmcgbW9ydGFsaXR5IHJlcHJlc2VudGVkICh0aW1lLWF2ZXJhZ2VkIGNhdGNoIGNvbXBhcmlzb24sIG1vZGVsIHZzIG9ic2VydmVkKSA9IGJhc2UgbW9kZWwNClN0ZXAgNDogY2hlY2sgYmFzZSBtb2RlbCB3aXRob3V0IGZpc2hpbmcgdG8gZW5zdXJlIGNvLWV4aXN0ZW5jZSBpcyBzdGlsbCBwcmVzZW50LCBvYnNlcnZlZCBiaW9tYXNzIHdvdWxkIG5vdCBiZSBzcGVjaWZpZWQNClN0ZXAgNTogRXhwZXJpbWVudHMgdGhyb3VnaCB0aW1lIC0gZWZmb3J0IGZ1bmN0aW9ucyAtIHVzZXMgdGhlIGJhc2UgbW9kZWwgd2l0aCBubyBmaXNoaW5nIGVmZm9ydCBhcyBhIHN0YXJ0aW5nIHBvaW50DQpTdGVwIDY6IEV4cG9zZSB0aGUgYmFzZSBtb2RlbCB0byBmaXNoaW5nIHRocm91Z2ggdGltZSBhbmQgY29tcGFyZSB0byBvYnNlcnZlZCBjYXRjaCB0aW1lIHNlcmllcyANCiAtIHN0YXJ0IGZyb20gMCBlZmZvcnQgYXQgZmlyc3QgdGltZS1zdGVwIHRvIG1heCBlZmZvcnQgYXBwcm94IGFyb3VuZCBjb2xsYXBzZQ0KIC0gSWYgdGhlIG1vZGVsbGVkIHZlcnN1cyBvYnNlcnZlZCBkb24ndCBtYXRjaCwgbmVlZCB0byBhZGp1c3QgZWZmb3J0L29yIGluaXRpYWwgYmlvbG9naWNhbCBwYXJhbXMgYW5kIGV4cGVyaW1lbnQgdG8gc2VlIHdoYXQgaW1wcm92ZXMNCiAtIGhhbmQgdHVuZSAvIG9wdGltIG9wdGlvbnMNCkFkanVzdCBhbmQgcmVjYWxpYnJhdGUgaWYgbmVlZGVkIChvcHRpbSkNClVzZSBydWxlcyB0byBjb25zdHJhaW4gLSBpLmUuLCANCi0gdGltZS1hdmVyYWdlZCBiaW9tYXNzZXMgd2l0aGluIGNhbGlicmF0aW9uIHBlcmlvZCBtdXN0IGJlICstIHh4ICUNCi0gY2FuIG9wdGltIHRoaW5ncyBsaWtlIGZpc2hpbmctc2l6ZSBzZWxlY3Rpdml0eSwgUFBNUnMgZXRjDQoNCg0KQ2FuIHdlIHJlcHJvZHVjZSB0aGUgdGltZSBzZXJpZXM/DQoNCg0KTG9hZCBsaWJyYXJpZXMgDQpgYGB7cn0NCnJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJzaXplc3BlY3RydW0vbWl6ZXJFeHBlcmltZW50YWwiKQ0KbGlicmFyeShtaXplckV4cGVyaW1lbnRhbCkNCiMgcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoInNpemVzcGVjdHJ1bS9taXplck1SIikNCiMgbGlicmFyeShtaXplck1SKQ0KIyBsaWJyYXJ5KG1pemVyKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHRpY3RvYykNCmxpYnJhcnkocGFyYWxsZWwpDQojIGxpYnJhcnkocGxvdGx5KQ0KYGBgDQoNCkNhdGNoIGRhdGEgZm9yIGFsbCBpbmRpdnVkYWxzIGFuZCBzdW1tYXJpc2VkIGFzIHRvdGFscyBwZXIgc3BlY2llcyBlYWNoIHllYXINCg0KTWF5YmUgdGhpcyBpc24ndCBleHByZXNzaW5nIGVmZm9ydCwgcmF0aGVyIGZpc2hpbmcgbW9ydGFsaXR5DQoNCg0KYGBge3J9DQojIGRmX2luZF9DUFVFIDwtIHJlYWRSRFMoImluZF9jYXRjaF93ZWlnaHRfQmFuemFyZUJhbmtfMTkzMF8yMDE5X0NQVUUucmRzIikNCiMgZGZfQ1BVRV9rZ19kYXkgPC0gcmVhZFJEUygiY2F0Y2hfdGltZXNlcmllc19CYW56YXJlQmFua18xOTMwXzIwMTlfQ1BVRS5yZHMiKQ0KIyANCiMgZ2xpbXBzZShkZl9pbmRfQ1BVRSkNCiMgZ2xpbXBzZShkZl9DUFVFX2tnX2RheSkNCmBgYA0KDQpZaWVsZCBmb3IgdGhlIHBlcmlvZCB0aGF0IG1hdGNoZXMgRWNvcGF0aCBtb2RlbCwgcG9zdCAyMDAwIGFubnVhbCBhdmVyYWdlDQpgYGB7cn0NCiMgZGZfeWllbGRfMjAwMCA8LSBkZl9DUFVFX2tnX2RheSAlPiUgDQojICAgZmlsdGVyKFllYXIgPiAyMDA5KSAlPiUgDQojICAgZ3JvdXBfYnkoU3BlY2llcykgJT4lIA0KIyAgIHN1bW1hcmlzZSh5aWVsZCA9IHN1bSh0b3RhbF9jYXRjaF9rZykvMTApDQojIA0KIyBkZl95aWVsZF8yMDAwDQpgYGANCg0KDQoNCmVmZm9ydF9kYXlzL21heCB2YWx1ZSBwbG90dGVkIGJ5IHNwZWNpZXMNClRoaXMgbWlnaHQgaW5kaWNhdGUgdGhlIGVmZm9ydCBjdXJ2ZSByZXF1aXJlZCwgZXNwZWNpYWxseSBpZiB0aGVyZSBpcyBhIGRpZmZlcmVuY2UgYmV0d2VlbiBkaWZmZXJlbnQgc3BlY2llcw0KYGBge3J9DQojIGRmX3Bsb3QgPC0gZGZfQ1BVRV9rZ19kYXkgJT4lIA0KIyAgIGZpbHRlcihZZWFyID4gMjAwMCkgJT4lIA0KIyAgIGdyb3VwX2J5KFNwZWNpZXMpICU+JSANCiMgICBtdXRhdGUobWF4X2VmZm9ydCA9IG1heChlZmZvcnRfZGF5cykpICU+JSANCiMgICBncm91cF9ieShTcGVjaWVzLFllYXIpICU+JSANCiMgICBtdXRhdGUoZWZmb3J0X3N0YW5kYXJkID0gZWZmb3J0X2RheXMvbWF4X2VmZm9ydCkNCmBgYA0KDQpSZWxhdGl2ZSBjaGFuZ2UgaW4gY2F0Y2ggcHJlLTE5MzAsIGNvdWxkIGluZm9ybSB0aGUgcmVsYXRpdmUgY2hhbmdlIGluIGVmZm9ydA0KQXNrIENhbWksIGhvdyBjb3VsZCBJIHJlY29uc3RydWN0IHRoZSBlZmZvcnQgdG8gdGhlIGluaXRpYWwgcG9pbnQgb2YgY2F0Y2ggd2hlbiBlZmZvcnQgPSAwLi4uaS5lLiwgYXBwcm94IDE4NTAgDQpgYGB7cn0NCiMgZGZfcGxvdCAlPiUgDQojICAgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IGVmZm9ydF9zdGFuZGFyZCwgY29sb3VyID0gU3BlY2llcykpICsNCiMgICBnZW9tX3Ntb290aCgpICsNCiMgICBnZW9tX2xpbmUoKQ0KIyAgICMgZmFjZXRfd3JhcCh+U3BlY2llcykgDQpgYGANCg0KYGBge3J9DQojIGRmX3Bsb3QgJT4lIA0KIyAgIGdncGxvdChhZXMoeCA9IFllYXIsIHkgPSBDUFVFLCBjb2xvdXIgPSBTcGVjaWVzKSkgKw0KIyAgICMgZ2VvbV9zbW9vdGgoKSArDQojICAgZ2VvbV9saW5lKCkNCiMgICAjIGZhY2V0X3dyYXAoflNwZWNpZXMpIA0KYGBgDQoNCkxvYWQgY2F0Y2ggbGVuZ3RoDQpgYGB7cn0NCmNhdGNoX2xlbmd0aHMgPC0gcmVhZFJEUygiY2F0Y2hfbGVuZ3Rocy5yZHMiKQ0KDQpnbGltcHNlKGNhdGNoX2xlbmd0aHMpDQpgYGANClRoZSB2YWx1ZSBmb3IgZXVwaGF1c2lpZHMgYG9ic195aWVsZGAgaXMgZnJvbSAgYGNhbGlicmF0aW9uX2NhdGNoX2hpc3Rzb2NfMTg1MF8yMDA0X3JlZ2lvbmFsX21vZGVscy5jc3ZgIGZvdW5kIGF0IGh0dHA6Ly9wb3J0YWwuc2YudXRhcy5lZHUuYXUvdGhyZWRkcy9jYXRhbG9nL2dlbS9maXNobWlwL0lTSU1JUDNhL0lucHV0RGF0YS9maXNoaW5nL2hpc3Rzb2MvY2F0YWxvZy5odG1sLiBJdCBpcyB0aGUgYW5udWFsIGF2ZXJhZ2UgeWllbGQgb3ZlciBhIDIyIHllYXIgcGVyaW9kIGZvciB0aGUgUHJ5ZHogQmF5IFJlZ2lvbi4NCg0KVGhlIHZhbHVlcyBvZiBgb2JzX3lpZWxkYCBmb3IgbWlua2Ugd2hhbGVzICgyMTc1NDc2MTM2KSwgb3JjYSAoMTk5MjM3MjkpLCBzcGVybSB3aGFsZXMgKDQwNjIxNzc0NDUpLCBhbmQgYmFsZWVuIHdoYWxlcyAoNTAzNDE2OTYwNTUpIGFyZSB0aGUgYW5udWFsIGF2ZXJhZ2UgeWllbGQgZnJvbSAxOTMwIC0gMjAxOSBmcm9tIElXQyByZWNvcmRzIG9mIHdoYWxpbmcgaW4gdGhlIFByeWR6IEJheSBtb2RlbCBkb21haW4gKDEsNDMzLDAyOCBrbTIpLg0KDQpBZGp1c3QgdGhlIGNhdGNoIHRvIHJlcHJlc2VudCB0aGUgMjAxMCAtIDIwMjAgdGltZSBwZXJpb2QgKyBpbmNvcnBvcmF0ZSB0b290aGZpc2ggY2F0Y2ggaWYgcG9zc2libGUgKGkuZS4sIFN0YWNleSdzIHBhcGVyIHZhbHVlcykNCg0KDQoNCg0KYGBge3J9DQpkZl9pbmRfQ1BVRSA8LSByZWFkUkRTKCJpbmRfY2F0Y2hfd2VpZ2h0X0JhbnphcmVCYW5rXzE5MzBfMjAxOV9DUFVFLnJkcyIpDQpkZl9DUFVFX2tnX2RheSA8LSByZWFkUkRTKCJjYXRjaF90aW1lc2VyaWVzX0JhbnphcmVCYW5rXzE5MzBfMjAxOV9DUFVFLnJkcyIpDQoNCmdsaW1wc2UoZGZfaW5kX0NQVUUpDQpnbGltcHNlKGRmX0NQVUVfa2dfZGF5KQ0KYGBgDQoNCllpZWxkIGZvciB0aGUgcGVyaW9kIHRoYXQgbWF0Y2hlcyBFY29wYXRoIG1vZGVsLCBwb3N0IDIwMDAgYW5udWFsIGF2ZXJhZ2UNCmBgYHtyfQ0KZGZfeWllbGRfMjAwMF8yMDE5IDwtIGRmX0NQVUVfa2dfZGF5ICU+JSANCiAgZmlsdGVyKFllYXIgPiAyMDAwKSAlPiUgDQogIGdyb3VwX2J5KFNwZWNpZXMpICU+JSANCiAgc3VtbWFyaXNlKHlpZWxkID0gc3VtKHRvdGFsX2NhdGNoX2tnKS8xOSkNCg0KZGZfeWllbGRfMjAwMF8yMDE5DQpgYGANCg0KQWRkIHlpZWxkIGluIHRvbm5lcyBwZXIga20yLCBzYW1lIGFzIGcgbTIgYW5kIGl0IGlzIGNvbnNpc3RlbnQgd2l0aCBgYmlvbWFzc19vYnNlcnZlZGAgDQoNCjEuNDc0MzQxZSsxMiBtXjIgZm9yIG1vZGVsIGRvbWFpbg0KDQoxLjQ3NDM0MWUrMTIvMWUrNiA9IDE0NzQzNDEga21eMg0KDQo1MDc1MTEga2cgb2YgbWlua2Ugd2hhbGUgcGVyIHllYXIgZnJvbSAyMDAwIC0gMjAxOQ0KDQo1MDcuNS8xNDc0MzQxID0gMC4wMDAzNDQyMjE2IHRvbm5lcyBNaW5rZSB3aGFsZSB5aWVsZCBwZXIga20yIGZyb20gMjAwMCAtIDIwMTkNCg0KMTU2MTkuMjQga2cgb2YgYmFsZWVuIHdoYWxlIHBlciB5ZWFyIGZyb20gMjAwMCAtIDIwMTkNCg0KMTUuNi8xNDc0MzQxID0gMS4wNTgxZS0wNSB0b25uZXMgb2YgYmFsZWVuIHdoYWxlIHBlciBrbTIgZnJvbSAyMDAwIC0gMjAxOQ0KDQpgYGB7cn0NCm9ic195aWVsZCA8LSBjKDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAuMDAwMzQ0MjIxNiwgMCwgMCwgMS4wNTgxZS0wNSkgIyB0byBhZGQgYSB5aWVsZF9vYnNlcnZlZCBjb2x1bW4gaW4gc3BlY2llc19wYXJhbXMNCg0KYGBgDQoNCg0KYGBge3J9DQpiaW9tYXNzX2N1dG9mZiA8LSBjKDAuMSwgMSwgMSwgMSwgNDAsIDQ1MDAsIDEsIDEsIDIwMDAwMCwgMTAwMDAsIDEzNTAwMCwgNjAwMDAwLCA0OTAwMDAsIDM2NTAwMDAsIDIyNTAwMDApICMgdG8gYWRkIGEgYmlvbWFzc19jdXRvZmYgY29sdW1uIGluIHNwZWNpZXNfcGFyYW1zDQoNCmBgYA0KDQoNClN0ZWFkeS1zdGF0ZSBtb2RlbCB3aXRoIG5vIGZpc2hpbmcgZWZmb3J0IGNhbGlicmF0ZWQgdG8gb2JzZXJ2ZWQgYmlvbWFzcyB2YWx1ZXMgZnJvbSBNY0Nvcm1hY2sgZXQgYWwuIDIwMjAgdGhhdCByZXByZXNlbnQgYW4gYXZlcmFnZSBzdGF0ZSBvZiB0aGUgZm9vZCB3ZWIgZnJvbSAyMDEwLTIwMjAuDQoNCmBgYHtyfQ0KIyBwYXJhbXMgPC0gIHJlYWRSRFMoInN0YWdlMV9zdGVhZHlfdlhYLnJkcyIpICMgSW5jb3JyZWN0IG9yY2EgYW5kIGxlb3BhcmQgc2VhbCB3X21heCB2YWx1ZXMNCnNvX3BhcmFtcyA8LSByZWFkUkRTKCJwYXJhbXNfMTZfTWFyY2hfMjAyMy5yZHMiKSAjIFVwZGF0ZWQgd19tYXggZm9yIG9yY2EgYW5kIGxlb3BhcmQgc2VhbHMNCg0KIyBwYXJhbXMgPC0gc2V0UGFyYW1zKHNldEZpc2hpbmcocGFyYW1zLCBpbml0aWFsX2VmZm9ydCA9IDAuMikpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBzcGVjaWVzX3BhcmFtcyhwYXJhbXMpJHlpZWxkX29ic2VydmVkIDwtIG9ic195aWVsZA0KIyBzcGVjaWVzX3BhcmFtcyhwYXJhbXMpJGJpb21hc3NfY3V0b2ZmIDwtIGJpb21hc3NfY3V0b2ZmDQojIHNwZWNpZXNfcGFyYW1zKHBhcmFtcykkYmlvbWFzc19jdXRvZmZMb3cgPC0gYmlvbWFzc19jdXRvZmYNCiMgc3BlY2llc19wYXJhbXMocGFyYW1zKSRiaW9tYXNzX2N1dG9mZkhpZ2ggPC0gc3BlY2llc19wYXJhbXMocGFyYW1zKSR3X21heA0KDQpzcGVjaWVzX3BhcmFtcyhzb19wYXJhbXMpJHlpZWxkX29ic2VydmVkIDwtIG9ic195aWVsZA0Kc3BlY2llc19wYXJhbXMoc29fcGFyYW1zKSRiaW9tYXNzX2N1dG9mZiA8LSBiaW9tYXNzX2N1dG9mZg0Kc3BlY2llc19wYXJhbXMoc29fcGFyYW1zKSRiaW9tYXNzX2N1dG9mZkxvdyA8LSBiaW9tYXNzX2N1dG9mZg0Kc3BlY2llc19wYXJhbXMoc29fcGFyYW1zKSRiaW9tYXNzX2N1dG9mZkhpZ2ggPC0gc3BlY2llc19wYXJhbXMoc29fcGFyYW1zKSR3X21heA0KDQojIHNwZWNpZXNfcGFyYW1zKHBhcmFtcykgfD4gZHBseXI6OnNlbGVjdChzcGVjaWVzLCB5aWVsZF9vYnNlcnZlZCwgd19tYXQsIHdfbWF4LCBSX21heCkNCnNwZWNpZXNfcGFyYW1zKHNvX3BhcmFtcykgfD4gZHBseXI6OnNlbGVjdChzcGVjaWVzLCB5aWVsZF9vYnNlcnZlZCwgd19tYXQsIHdfbWF4LCBSX21heCkNCmBgYA0KDQoNCg0KYGBge3J9DQojIGdyb3VwcyB8PiBkcGx5cjo6c2VsZWN0KHNwZWNpZXMsIHlpZWxkX29ic2VydmVkLCBiaW9tYXNzX29ic2VydmVkLCBiaW9tYXNzX2N1dG9mZiwgd19taW4pDQpgYGANCg0KDQpgYGB7cn0NCiMgeWllbGRfb2JzZXJ2ZWQgPC0gYygwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLjAwMDM0NDIyMTYsIDAsIDAsIDEuMDU4MWUtMDUpICMgdG8gYWRkIGEgeWllbGRfb2JzZXJ2ZWQgY29sdW1uIGluIHNwZWNpZXNfcGFyYW1zDQojIA0KIyBzcGVjaWVzX3BhcmFtcyhwYXJhbXMpJHlpZWxkX29ic2VydmVkIDwtIHlpZWxkX29ic2VydmVkDQpgYGANCg0KYGBge3J9DQojIGJpb21hc3NfY3V0b2ZmIDwtIGMoMC4xLCAxLCAxLCAxLCA0MCwgNDUwMCwgMSwgMSwgMjAwMDAwLCAxMDAwMCwgMTM1MDAwLCA2MDAwMDAsIDQ5MDAwMCwgMzY1MDAwMCwgMjI1MDAwMCkgIyB0byBhZGQgYSBiaW9tYXNzX2N1dG9mZiBjb2x1bW4gaW4gc3BlY2llc19wYXJhbXMNCiMgDQojIHNwZWNpZXNfcGFyYW1zKHBhcmFtcykkYmlvbWFzc19jdXRvZmYgPC0gYmlvbWFzc19jdXRvZmYNCmBgYA0KDQpVcGRhdGUgbWF4IGFuZCBtYXQgc2l6ZSBmb3Igb3JjYSB1c2luZyBzZWFsaWZlYmFzZSB2YWx1ZXMgcmF0aGVyIHRoYW4gdGhlIHByZXZpb3VzIHdfbWF4IG9mIDZ0DQpgYGB7cn0NCiMgc3BlY2llc19wYXJhbXMocGFyYW1zKSRzcGVjaWVzWzEzXQ0KIyBzcGVjaWVzX3BhcmFtcyhwYXJhbXMpJHdfbWF4WzEzXQ0KIyBzcGVjaWVzX3BhcmFtcyhwYXJhbXMpJHdfbWF0WzEzXQ0KIyANCiMgc3BlY2llc19wYXJhbXMocGFyYW1zKSR3X21heFsxM10gPC0gMTA2MjgwMzQNCiMgDQojIHNwZWNpZXNfcGFyYW1zKHBhcmFtcykkd19tYXRbMTNdIDwtIDMxOTg4NTUNCiMgDQojIHNwZWNpZXNfcGFyYW1zKHBhcmFtcykkd19tYXhbMTNdDQojIHNwZWNpZXNfcGFyYW1zKHBhcmFtcykkd19tYXRbMTNdDQojIHNwZWNpZXNfcGFyYW1zKHBhcmFtcykkd19tYXQyNVsxM10NCmBgYA0KDQoNClVwZGF0ZSBtYXggYW5kIG1hdCBzaXplIGZvciBsZW9wYXJkIHNlYWwgdXNpbmcgc2VhbGlmZWJhc2UgdmFsdWVzLiBNYXggd2VpZ2h0IG9ic2VydmVkIHJlcG9ydGVkIGFzIDQ1MGtnLiBVc2luZyB0aGUgc2VhbGlmZWJhc2UgdmFsdWVzIGZvciBMLVcgY29udmVyc2lvbiBhbmQgbWF4IGxlbmd0aCByZXN1bHRzIGluIGFuIGVzdGltYXRlZCBtYXggd2VpZ2h0IG9mIDU0NTg3NS4yZywgd2hpY2ggaXMgdG9vIGhpZ2ggYWJvdmUgdGhlIG1heCB3ZWlnaHQgb2JzZXJ2ZWQuDQpgYGB7cn0NCiMgc3BlY2llc19wYXJhbXMocGFyYW1zKSRzcGVjaWVzWzldDQojIHNwZWNpZXNfcGFyYW1zKHBhcmFtcykkd19tYXhbOV0NCiMgc3BlY2llc19wYXJhbXMocGFyYW1zKSR3X21hdFs5XQ0KIyANCiMgc3BlY2llc19wYXJhbXMocGFyYW1zKSR3X21heFs5XSA8LSA0NTAwMDANCiMgIA0KIyBzcGVjaWVzX3BhcmFtcyhwYXJhbXMpJHdfbWF4WzldDQojIHNwZWNpZXNfcGFyYW1zKHBhcmFtcykkd19tYXRbOV0NCiMgc3BlY2llc19wYXJhbXMocGFyYW1zKSR3X21hdDI1WzldDQpgYGANCg0KQWRqdXN0IGB3X21hdGAgdmFsdWVzIHRoYXQgd2VyZSBjaGFuZ2VkIGJ5IGRlZmF1bHQgaW4gYG5ld011bHRpc3BlY2llc1BhcmFtc2ANCmBgYHtyfQ0KIyBwYXJhbXNfdjEgPC0gcGFyYW1zDQojIA0KIyBwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkd19tYXRbcGFyYW1zX3YxQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gImxhcmdlIGRpdmVycyJdICA8LSBwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkd19tYXhbcGFyYW1zX3YxQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gImxhcmdlIGRpdmVycyJdICogMC45DQojIHBhcmFtc192MUBzcGVjaWVzX3BhcmFtcyR3X21hdFtwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAibWlua2Ugd2hhbGVzIl0gIDwtIHBhcmFtc192MUBzcGVjaWVzX3BhcmFtcyR3X21heFtwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAibWlua2Ugd2hhbGVzIl0gKiAwLjkNCiMgcGFyYW1zX3YxQHNwZWNpZXNfcGFyYW1zJHdfbWF0W3BhcmFtc192MUBzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJvcmNhIl0gIDwtIHBhcmFtc192MUBzcGVjaWVzX3BhcmFtcyR3X21heFtwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAib3JjYSJdICogMC45DQojIHBhcmFtc192MUBzcGVjaWVzX3BhcmFtcyR3X21hdFtwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAic3Blcm0gd2hhbGVzIl0gIDwtIHBhcmFtc192MUBzcGVjaWVzX3BhcmFtcyR3X21heFtwYXJhbXNfdjFAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAic3Blcm0gd2hhbGVzIl0gKiAwLjkNCiMgDQojIHBhcmFtc192MSA8LSBzZXRQYXJhbXMocGFyYW1zX3YxKQ0KYGBgDQoNCg0KYGBge3J9DQojIHBhcmFtc192MiA8LSBwYXJhbXNfdjENCiMgDQojIHBhcmFtc192MkBzcGVjaWVzX3BhcmFtcyR3X21pbltwYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAic21hbGwgZGl2ZXJzIl0gIDwtIHBhcmFtc192MkBzcGVjaWVzX3BhcmFtcyR3X21hdFtwYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAic21hbGwgZGl2ZXJzIl0gKiAwLjg1DQojIHBhcmFtc192MkBzcGVjaWVzX3BhcmFtcyR3X21pbltwYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkc3BlY2llcyA9PSAibGVvcGFyZCBzZWFscyJdICA8LSBwYXJhbXNfdjJAc3BlY2llc19wYXJhbXMkd19tYXRbcGFyYW1zX3YyQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gImxlb3BhcmQgc2VhbHMiXSAqIDAuODUNCiMgDQojIHBhcmFtc192MiA8LSBzZXRQYXJhbXMocGFyYW1zX3YyKQ0KYGBgDQoNCg0KYGBge3J9DQpwYXJhbXMgPC0gc3RlYWR5KHNvX3BhcmFtcykNCmBgYA0KDQpDaGVjayBnZWFyIHBhcmFtcw0KDQpgYGB7cn0NCmdlYXJfcGFyYW1zKHBhcmFtcykNCmBgYA0KDQpBZGp1c3QgY2F0Y2hhYmlsaXR5IHRvIG9ubHkgc2VsZWN0IGZpc2hpbmcgb24gc3BlY2llcyB3aXRoIGNhdGNoIGRhdGENClRoaXMgaXMgYSBvbmx5IHN0YXJ0aW5nIHBvaW50DQpgYGB7cn0NCmdlYXJfcGFyYW1zKHBhcmFtcykkY2F0Y2hhYmlsaXR5IDwtICBjKDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAuNDksIDAsIDAsIDAuMDAxKQ0KYGBgDQoNCg0KQ2F0Y2hhYmlsaXR5OiAxIHZhbHVlIA0KRWZmb3J0IGNoYW5nZXMgdGhyb3VnaCB0aW1lICh2b3lhZ2UgZnJlcXVlbmN5IGFuZCBsZW5ndGgpDQoNCmBgYHtyfQ0KZ2Vhcl9wYXJhbXMocGFyYW1zKSRnZWFyIDwtICBjKCJNYWluIiwgIk1haW4iLCAiTWFpbiIsICJNYWluIiwgIk1haW4iLCAiTWFpbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNYWluIiwgIk1haW4iLCAiTWFpbiIsICJNYWluIiwgIk1haW4iLCAiTWFpbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNYWluIiwgIk1haW4iLCAiTWFpbiIpDQoNCmdlYXJfcGFyYW1zKHBhcmFtcykkbDUwIDwtICBjKDEsIDUsIDUsIDUsIDEwLCAxMCwgMTAsIDIwLCAyMCwgMjAsIDIwLCA4NTAsIDYwMCwgMTUwMCwgMjIwMCkgIyB2YWx1ZXMgZm9yIG1pbmtlLCBvcmNhLCBzcGVybSBhbmQgYmFsZWVuIGFyZSBlc3RpbWF0ZWQgYmFzZWQgb2ZmIGBjYXRjaF9sZW5ndGhzYCwgd2hpbGUgYWxsIG90aGVycyBhcmUgcm91Z2ggZ3Vlc3NlcywgcHVyZWx5IGFzIHRoZSBwYXJhbSB3b24ndCB3b3JrIHdpdGggdmFsdWVzIG1pc3NpbmcuDQoNCmdlYXJfcGFyYW1zKHBhcmFtcykkbDI1IDwtICBjKDAuOCwgNCwgNCwgNCwgOCwgOCwgOCwgMTYsIDE2LCAxNiwgMTYsIDgwMCwgNTAwLCAxNDAwLCAxNTAwKQ0KDQpnZWFyX3BhcmFtcyhwYXJhbXMpJHNlbF9mdW5jIDwtICBjKCJzaWdtb2lkX2xlbmd0aCIsICJzaWdtb2lkX2xlbmd0aCIsICJzaWdtb2lkX2xlbmd0aCIsICJzaWdtb2lkX2xlbmd0aCIsICJzaWdtb2lkX2xlbmd0aCIsICJzaWdtb2lkX2xlbmd0aCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzaWdtb2lkX2xlbmd0aCIsICJzaWdtb2lkX2xlbmd0aCIsICJzaWdtb2lkX2xlbmd0aCIsICJzaWdtb2lkX2xlbmd0aCIsICJzaWdtb2lkX2xlbmd0aCIsICJzaWdtb2lkX2xlbmd0aCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzaWdtb2lkX2xlbmd0aCIsICJzaWdtb2lkX2xlbmd0aCIsICJzaWdtb2lkX2xlbmd0aCIpDQoNCmdlYXJfcGFyYW1zKHBhcmFtcykNCmBgYA0KDQoNCmBgYHtyfQ0KcGFyYW1zX3YwMiA8LSBzZXRQYXJhbXMoc2V0RmlzaGluZyhwYXJhbXMsIGluaXRpYWxfZWZmb3J0ID0gMC4yKSkNCg0KcGFyYW1zX3YwMiA8LSBzdGVhZHkocGFyYW1zX3YwMikNCg0Kc2ltX3YwMSA8LSBwcm9qZWN0KHBhcmFtc192MDIsIHRfbWF4ID0gMTAwKQ0KcGxvdChzaW1fdjAxKQ0KcGxvdGx5QmlvbWFzcyhzaW1fdjAxKQ0Kc2ltX3YwMUBwYXJhbXNAaW5pdGlhbF9lZmZvcnQNCmBgYA0KDQoNCmBgYHtyfQ0KcGxvdFlpZWxkVnNTaXplKHNpbV92MDEsIHNwZWNpZXMgPSAiYmFsZWVuIHdoYWxlcyIsIGNhdGNoID0gY2F0Y2hfbGVuZ3RocywgDQogICAgICAgICAgICAgICAgeF92YXIgPSAiTGVuZ3RoIikNCg0KIyBwbG90WWllbGRWc1NpemUoc2ltX3YxLCBzcGVjaWVzID0gInNwZXJtIHdoYWxlcyIsIGNhdGNoID0gY2F0Y2hfbGVuZ3RocywgDQojICAgICAgICAgICAgICAgICB4X3ZhciA9ICJMZW5ndGgiKQ0KIyANCiMgcGxvdFlpZWxkVnNTaXplKHNpbV92MSwgc3BlY2llcyA9ICJvcmNhIiwgY2F0Y2ggPSBjYXRjaF9sZW5ndGhzLCANCiMgICAgICAgICAgICAgICAgIHhfdmFyID0gIkxlbmd0aCIpDQoNCnBsb3RZaWVsZFZzU2l6ZShzaW1fdjAxLCBzcGVjaWVzID0gIm1pbmtlIHdoYWxlcyIsIGNhdGNoID0gY2F0Y2hfbGVuZ3RocywgDQogICAgICAgICAgICAgICAgeF92YXIgPSAiTGVuZ3RoIikNCmBgYA0KDQpgYGB7cn0NCmdldEVycm9yQ3VzdG9tIDwtIGZ1bmN0aW9uKHZhcnksIHBhcmFtcywgZGF0LCB0b2wgPSAwLjAwMSwgDQogICAgdGltZXRvcnVuID0gMTApDQp7DQogIHBhcmFtc0BzcGVjaWVzX3BhcmFtcyRSX21heFsxOjE1XTwtMTBedmFyeVsxOjE1XSAjIFJfbWF4IGZvciAxNSBzcGVjaWVzDQogIHBhcmFtc0BzcGVjaWVzX3BhcmFtcyRlcmVwcm9bMToxNV08LXZhcnlbMTY6MzBdICMgZXJlcHJvIGZvciAxNSBzcGVjaWVzDQogIHBhcmFtc0BzcGVjaWVzX3BhcmFtcyRpbnRlcmFjdGlvbl9yZXNvdXJjZVsxOjE1XSA8LSB2YXJ5WzMxOjQ1XSAjIGludGVyYWN0aW9uX3Jlc291cmNlIGZvciAxNSBzcGVjaWVzDQogIHBhcmFtcyA8LSBzZXRQYXJhbXMocGFyYW1zKQ0KICAjIGludGVyYWN0aW9uIDwtIHBhcmFtc0BpbnRlcmFjdGlvbg0KICAjIGludGVyYWN0aW9uW10gPC0gbWF0cml4KHZhcnlbMjg6MTA4XSxucm93ID0gOSkgIyBzdG9wIGF0IDU0IGlmIGxvb2tpbmcgb25seSBhdCAzIGJpZ2dlc3Qgc3BlY2llcw0KICANCiAgIyBwYXJhbXMgPC0gc2V0SW50ZXJhY3Rpb24ocGFyYW1zLGludGVyYWN0aW9uKQ0KICAgIHBhcmFtcyA8LSBwcm9qZWN0VG9TdGVhZHkocGFyYW1zLCBkaXN0YW5jZV9mdW5jID0gZGlzdGFuY2VTU0xvZ04sIA0KICAgICAgICB0b2wgPSB0b2wsIHRfbWF4ID0gMjAwLCByZXR1cm5fc2ltID0gRikNCiAgICANCiAgICBzaW0gPC0gcHJvamVjdChwYXJhbXMsIHRfbWF4ID0gdGltZXRvcnVuLCBwcm9ncmVzc19iYXIgPSBGKQ0KICAgIA0KICAgIHNpbV9iaW9tYXNzID0gcmVwKDAsIGxlbmd0aChwYXJhbXNAc3BlY2llc19wYXJhbXMkc3BlY2llcykpDQogICAgDQogICAgICAgIGN1dG9mZkxvdyA8LSBwYXJhbXNAc3BlY2llc19wYXJhbXMkYmlvbWFzc19jdXRvZmZMb3cNCiAgICBpZiAoaXMubnVsbChjdXRvZmZMb3cpKSANCiAgICAgICAgY3V0b2ZmTG93IDwtIHJlcCgwLCBub19zcCkNCiAgICBjdXRvZmZMb3dbaXMubmEoY3V0b2ZmTG93KV0gPC0gMA0KICAgIA0KICAgICAgICBjdXRvZmZIaWdoIDwtIHBhcmFtc0BzcGVjaWVzX3BhcmFtcyRiaW9tYXNzX2N1dG9mZkhpZ2gNCiAgICBpZiAoaXMubnVsbChjdXRvZmZIaWdoKSkgDQogICAgICAgIGN1dG9mZkhpZ2ggPC0gcmVwKDAsIG5vX3NwKQ0KICAgIGN1dG9mZkhpZ2hbaXMubmEoY3V0b2ZmSGlnaCldIDwtIDANCiAgICAgICAgDQogICAgZm9yIChqIGluIDE6bGVuZ3RoKHNpbV9iaW9tYXNzKSkgew0KICAgICAgICBzaW1fYmlvbWFzc1tqXSA9IHN1bSgoc2ltQG5bZGltKHNpbUBuKVsxXSxqLF0gKiBwYXJhbXNAdyAqIA0KICAgICAgICAgICAgcGFyYW1zQGR3KVtwYXJhbXNAdyA+PSBjdXRvZmZMb3dbal0gJiBjdXRvZmZIaWdoW2pdID49IHBhcmFtc0B3XSkNCiAgICB9DQogICAgDQogICAgIHByZWQgPC0gbG9nKHNpbV9iaW9tYXNzKQ0KICAgIGRhdCA8LSBsb2coZGF0KQ0KICAgIGRpc2NyZXAgPC0gcHJlZCAtIGRhdA0KICAgIGRpc2NyZXAgPC0gKHN1bShkaXNjcmVwXjIpKQ0KICAgIHJldHVybihkaXNjcmVwKQ0KfQ0KICAgIA0KYGBgDQoNCg0KYGBge3J9DQojIGNyZWF0ZSBzZXQgb2YgcGFyYW1zIGZvciB0aGUgb3B0aW1pc2F0aW9uIHByb2Nlc3MNCnRpYygpDQoNCnBhcmFtc19vcHRpbSA8LSBwYXJhbXNfdjAyDQoNCnZhcnkgPC0gYyhsb2cxMChwYXJhbXNfb3B0aW1Ac3BlY2llc19wYXJhbXMkUl9tYXgpLA0KICAgICAgICAgIHBhcmFtc19vcHRpbUBzcGVjaWVzX3BhcmFtcyRlcmVwcm8sDQogICAgICAgICAgcGFyYW1zX29wdGltQHNwZWNpZXNfcGFyYW1zJGludGVyYWN0aW9uX3Jlc291cmNlKQ0KDQpwYXJhbXNfb3B0aW08LXNldFBhcmFtcyhwYXJhbXNfb3B0aW0pDQoNCiMgc2V0IHVwIHdvcmtlcnMNCm5vQ29yZXMgPC0gcGFyYWxsZWw6OmRldGVjdENvcmVzKCkgLSAxICMga2VlcCBzb21lIHNwYXJlIGNvcmUNCmNsIDwtIHBhcmFsbGVsOjptYWtlQ2x1c3Rlcihub0NvcmVzLCBzZXR1cF90aW1lb3V0ID0gMC41KQ0Kc2V0RGVmYXVsdENsdXN0ZXIoY2wgPSBjbCkNCmNsdXN0ZXJFeHBvcnQoY2wsIHZhcmxpc3QgPSAiY2wiLGVudmlyPWVudmlyb25tZW50KCkpDQpjbHVzdGVyRXZhbFEoY2wsIHsNCiAgbGlicmFyeShtaXplckV4cGVyaW1lbnRhbCkNCiAgbGlicmFyeShvcHRpbVBhcmFsbGVsKQ0KfSkNCg0Kb3B0aW1fcmVzdWx0IDwtIG9wdGltUGFyYWxsZWw6Om9wdGltUGFyYWxsZWwocGFyPXZhcnksZ2V0RXJyb3JDdXN0b20scGFyYW1zPXBhcmFtc19vcHRpbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXQgPSBwYXJhbXNfb3B0aW1Ac3BlY2llc19wYXJhbXMkYmlvbWFzc19vYnNlcnZlZCwgbWV0aG9kID0iTC1CRkdTLUIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyPWMocmVwKC0xNSwxNSkscmVwKDFlLTcsMTUpLHJlcCguMSwxNSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXI9IGMocmVwKDE1LDE1KSxyZXAoMSwxNSkscmVwKC45OSwxNSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYWxsZWw9bGlzdChsb2dpbmZvPVRSVUUsIGZvcndhcmQ9VFJVRSkpDQpzdG9wQ2x1c3RlcihjbCkNCg0KdG9jKCkNCg0Kc2F2ZVJEUyhvcHRpbV9yZXN1bHQsIGZpbGU9Im9wdGltX3Jlc3VsdF92MDAuUkRTIikNCiMgb3B0aW1fcmVzdWx0IDwtIHJlYWRSRFMoIm9wdGltX3Jlc3VsdF92MDAuUkRTIikNCmBgYA0KDQoNCmBgYHtyfQ0KI3B1dCB0aGVzZSBuZXcgdmFscyBpbnRvc3BlY2llc19wYXJhbXMgYW5kIGdvIGJhY2sgdG8gdGhlIHRvcCBvZiB0aGlzIHBhZ2UgdG8gcmUtY2hlY2sgdGhlIGNhbGlicmF0aW9uIA0Kc3BlY2llc19wYXJhbXMocGFyYW1zX29wdGltKSRSX21heDwtMTBeb3B0aW1fcmVzdWx0JHBhclsxOjE1XQ0Kc3BlY2llc19wYXJhbXMocGFyYW1zX29wdGltKSRlcmVwcm88LW9wdGltX3Jlc3VsdCRwYXJbMTY6MzBdDQpzcGVjaWVzX3BhcmFtcyhwYXJhbXNfb3B0aW0pJGludGVyYWN0aW9uX3Jlc291cmNlIDwtb3B0aW1fcmVzdWx0JHBhclszMTo0NV0NCiANCnNpbV9vcHRpbSA8LSBwcm9qZWN0KHBhcmFtc19vcHRpbSwgdF9tYXggPSAyMDAwKQ0KcGxvdEJpb21hc3Moc2ltX29wdGltKQ0KYGBgDQoNCmBgYHtyfQ0KI3B1dCB0aGVzZSBuZXcgdmFscyBpbnRvc3BlY2llc19wYXJhbXMgYW5kIGdvIGJhY2sgdG8gdGhlIHRvcCBvZiB0aGlzIHBhZ2UgdG8gcmUtY2hlY2sgdGhlIGNhbGlicmF0aW9uIA0Kc3BlY2llc19wYXJhbXMocGFyYW1zX29wdGltKSRSX21heA0Kc3BlY2llc19wYXJhbXMocGFyYW1zX29wdGltKSRlcmVwcm8NCnNwZWNpZXNfcGFyYW1zKHBhcmFtc19vcHRpbSkkaW50ZXJhY3Rpb25fcmVzb3VyY2UNCmBgYA0KDQoNCmBgYHtyfQ0KIyB0aGlzIGZ1bmN0aW9uIGFkZHMgYSBsb3dlciBib3VuZGFyeSB0byBzZWxlY3RlZCBzaXplDQpwbG90QmlvbWFzc09ic2VydmVkVnNNb2RlbEN1c3RvbSA8LSBmdW5jdGlvbiAob2JqZWN0LCBzcGVjaWVzID0gTlVMTCwgcmF0aW8gPSBGQUxTRSwgbG9nX3NjYWxlID0gVFJVRSwgDQogICAgcmV0dXJuX2RhdGEgPSBGQUxTRSwgbGFiZWxzID0gVFJVRSwgc2hvd191bm9ic2VydmVkID0gRkFMU0UpIA0Kew0KICAgIGlmIChpcyhvYmplY3QsICJNaXplclNpbSIpKSB7DQogICAgICAgIHBhcmFtcyA9IG9iamVjdEBwYXJhbXMNCiAgICAgICAgbiA8LSBmaW5hbE4ob2JqZWN0KQ0KICAgIH0NCiAgICBlbHNlIGlmIChpcyhvYmplY3QsICJNaXplclBhcmFtcyIpKSB7DQogICAgICAgIHBhcmFtcyA9IG9iamVjdA0KICAgICAgICBuIDwtIGluaXRpYWxOKHBhcmFtcykNCiAgICB9DQogICAgZWxzZSB7DQogICAgICAgIHN0b3AoIllvdSBoYXZlIG5vdCBwcm92aWRlZCBhIHZhbGlkIG1pemVyU2ltIG9yIG1pemVyUGFyYW1zIG9iamVjdC4iKQ0KICAgIH0NCiAgICBzcF9wYXJhbXMgPC0gcGFyYW1zQHNwZWNpZXNfcGFyYW1zDQogICAgc3BlY2llcyA9IHZhbGlkX3NwZWNpZXNfYXJnKG9iamVjdCwgc3BlY2llcykNCiAgICBpZiAobGVuZ3RoKHNwZWNpZXMpID09IDApIA0KICAgICAgICBzdG9wKCJObyBzcGVjaWVzIHNlbGVjdGVkLCBwbGVhc2UgZml4LiIpDQogICAgcm93X3NlbGVjdCA9IG1hdGNoKHNwZWNpZXMsIHNwX3BhcmFtcyRzcGVjaWVzKQ0KICAgIGlmICghImJpb21hc3Nfb2JzZXJ2ZWQiICVpbiUgbmFtZXMoc3BfcGFyYW1zKSkgew0KICAgICAgICBzdG9wKCJZb3UgaGF2ZSBub3QgcHJvdmlkZWQgdmFsdWVzIGZvciB0aGUgY29sdW1uICdiaW9tYXNzX29ic2VydmVkJyAiLCANCiAgICAgICAgICAgICJpbiB0aGUgbWl6ZXJQYXJhbXMvbWl6ZXJTaW0gb2JqZWN0LiIpDQogICAgfQ0KICAgIGVsc2UgaWYgKCFpcy5udW1lcmljKHNwX3BhcmFtcyRiaW9tYXNzX29ic2VydmVkKSkgew0KICAgICAgICBzdG9wKCJUaGUgY29sdW1uICdiaW9tYXNzX29ic2VydmVkJyBpbiB0aGUgbWl6ZXJQYXJhbXMvbWl6ZXJTaW0gb2JqZWN0IiwgDQogICAgICAgICAgICAiIGlzIG5vdCBudW1lcmljLCBwbGVhc2UgZml4LiIpDQogICAgfQ0KICAgIGVsc2Ugew0KICAgICAgICBiaW9tYXNzX29ic2VydmVkID0gc3BfcGFyYW1zJGJpb21hc3Nfb2JzZXJ2ZWQNCiAgICB9DQogICAgDQogICAgY3V0b2ZmTG93IDwtIHNwX3BhcmFtcyRiaW9tYXNzX2N1dG9mZkxvd1tyb3dfc2VsZWN0XQ0KICAgIGlmIChpcy5udWxsKGN1dG9mZkxvdykpIHsNCiAgICAgICAgY3V0b2ZmTG93ID0gcmVwKDAsIGxlbmd0aChzcGVjaWVzKSkNCiAgICB9DQogICAgZWxzZSBpZiAoIWlzLm51bWVyaWMoY3V0b2ZmTG93KSkgew0KICAgICAgICBzdG9wKCJwYXJhbXNAc3BlY2llc19wYXJhbXMkYmlvbWFzc19jdXRvZmZMb3cgaXMgbm90IG51bWVyaWMsIFwiLFxuICAgICAgICAgICAgICAgICBcInBsZWFzZSBmaXguIikNCiAgICB9DQogICAgY3V0b2ZmTG93W2lzLm5hKGN1dG9mZkxvdyldIDwtIDANCiAgICANCiAgICBjdXRvZmZIaWdoIDwtIHNwX3BhcmFtcyRiaW9tYXNzX2N1dG9mZkhpZ2hbcm93X3NlbGVjdF0NCiAgICBpZiAoaXMubnVsbChjdXRvZmZIaWdoKSkgew0KICAgICAgICBjdXRvZmZIaWdoID0gcmVwKDAsIGxlbmd0aChzcGVjaWVzKSkNCiAgICB9DQogICAgZWxzZSBpZiAoIWlzLm51bWVyaWMoY3V0b2ZmSGlnaCkpIHsNCiAgICAgICAgc3RvcCgicGFyYW1zQHNwZWNpZXNfcGFyYW1zJGJpb21hc3NfY3V0b2ZmSGlnaCBpcyBub3QgbnVtZXJpYywgXCIsXG4gICAgICAgICAgICAgICAgIFwicGxlYXNlIGZpeC4iKQ0KICAgIH0NCiAgICBjdXRvZmZIaWdoW2lzLm5hKGN1dG9mZkhpZ2gpXSA8LSAwDQogICAgDQogICAgc2ltX2Jpb21hc3MgPSByZXAoMCwgbGVuZ3RoKHNwZWNpZXMpKQ0KICAgIGZvciAoaiBpbiAxOmxlbmd0aChzcGVjaWVzKSkgew0KICAgICAgICBzaW1fYmlvbWFzc1tqXSA9IHN1bSgobltyb3dfc2VsZWN0W2pdLCBdICogcGFyYW1zQHcgKiANCiAgICAgICAgICAgIHBhcmFtc0BkdylbcGFyYW1zQHcgPj0gY3V0b2ZmTG93W2pdICYgY3V0b2ZmSGlnaFtqXSA+PSBwYXJhbXNAd10pDQogICAgfQ0KICAgIGR1bW15ID0gZGF0YS5mcmFtZShzcGVjaWVzID0gc3BlY2llcywgbW9kZWwgPSBzaW1fYmlvbWFzcywgDQogICAgICAgIG9ic2VydmVkID0gYmlvbWFzc19vYnNlcnZlZFtyb3dfc2VsZWN0XSkgJT4lIG11dGF0ZShzcGVjaWVzID0gZmFjdG9yKHNwZWNpZXMsIA0KICAgICAgICBsZXZlbHMgPSBzcGVjaWVzKSwgaXNfb2JzZXJ2ZWQgPSAhaXMubmEob2JzZXJ2ZWQpICYgb2JzZXJ2ZWQgPiANCiAgICAgICAgMCwgb2JzZXJ2ZWQgPSBjYXNlX3doZW4oaXNfb2JzZXJ2ZWQgfiBvYnNlcnZlZCwgIWlzX29ic2VydmVkIH4gDQogICAgICAgIG1vZGVsKSwgcmF0aW8gPSBtb2RlbC9vYnNlcnZlZCkNCiAgICBpZiAoc3VtKGR1bW15JGlzX29ic2VydmVkKSA9PSAwKSB7DQogICAgICAgIGNhdChwYXN0ZSgiVGhlcmUgYXJlIG5vIG9ic2VydmVkIGJpb21hc3NlcyB0byBjb21wYXJlIHRvIG1vZGVsLCIsIA0KICAgICAgICAgICAgIm9ubHkgcGxvdHRpbmcgbW9kZWwgYmlvbWFzc2VzLiIsIHNlcCA9ICJcbiIpKQ0KICAgIH0NCiAgICBpZiAoIXNob3dfdW5vYnNlcnZlZCkgew0KICAgICAgICBkdW1teSA8LSBmaWx0ZXIoZHVtbXksIGlzX29ic2VydmVkKQ0KICAgIH0NCiAgICBpZiAocmV0dXJuX2RhdGEgPT0gVFJVRSkgDQogICAgICAgIHJldHVybihkdW1teSkNCiAgICB0cmUgPC0gcm91bmQoc3VtKGFicygxIC0gZHVtbXkkcmF0aW8pKSwgZGlnaXRzID0gMykNCiAgICBjYXB0aW9uIDwtIHBhc3RlMCgiVG90YWwgcmVsYXRpdmUgZXJyb3IgPSAiLCB0cmUpDQogICAgaWYgKGFueSghZHVtbXkkaXNfb2JzZXJ2ZWQpKSB7DQogICAgICAgIGNhcHRpb24gPC0gcGFzdGUoY2FwdGlvbiwgIlxuIE9wZW4gY2lyY2xlcyByZXByZXNlbnQgc3BlY2llcyB3aXRob3V0IGJpb21hc3Mgb2JzZXJ2YXRpb24uIikNCiAgICB9DQogICAgaWYgKHJhdGlvID09IEZBTFNFKSB7DQogICAgICAgIGdnIDwtIGdncGxvdChkYXRhID0gZHVtbXksIGFlcyh4ID0gb2JzZXJ2ZWQsIHkgPSBtb2RlbCwgDQogICAgICAgICAgICBjb2xvdXIgPSBzcGVjaWVzLCBzaGFwZSA9IGlzX29ic2VydmVkKSkgKyBnZW9tX2FibGluZShhZXMoaW50ZXJjZXB0ID0gMCwgDQogICAgICAgICAgICBzbG9wZSA9IDEpLCBjb2xvdXIgPSAicHVycGxlIiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgDQogICAgICAgICAgICBzaXplID0gMS4zKSArIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsgbGFicyh5ID0gIm1vZGVsIGJpb21hc3MgW2ddIikgKyANCiAgICAgICAgICAgIGNvb3JkX2NhcnRlc2lhbih5bGltID0gcmFuZ2UoZHVtbXkkbW9kZWwsIGR1bW15JG9ic2VydmVkKSkNCiAgICB9DQogICAgZWxzZSB7DQogICAgICAgIGdnIDwtIGdncGxvdChkYXRhID0gZHVtbXksIGFlcyh4ID0gb2JzZXJ2ZWQsIHkgPSByYXRpbywgDQogICAgICAgICAgICBjb2xvdXIgPSBzcGVjaWVzLCBzaGFwZSA9IGlzX29ic2VydmVkKSkgKyBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gMSksIA0KICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3VyID0gInB1cnBsZSIsIA0KICAgICAgICAgICAgc2l6ZSA9IDEuMykgKyBnZW9tX3BvaW50KHNpemUgPSAzKSArIGxhYnMoeSA9ICJtb2RlbCBiaW9tYXNzIC8gb2JzZXJ2ZWQgYmlvbWFzcyIpICsgDQogICAgICAgICAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IHJhbmdlKGR1bW15JHJhdGlvKSkNCiAgICB9DQogICAgZ2cgPC0gZ2cgKyBsYWJzKHggPSAib2JzZXJ2ZWQgYmlvbWFzcyBbZ10iLCBjYXB0aW9uID0gY2FwdGlvbikgKyANCiAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBnZXRDb2xvdXJzKHBhcmFtcylbZHVtbXkkc3BlY2llc10pICsgDQogICAgICAgIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKGBUUlVFYCA9IDE5LCBgRkFMU0VgID0gMSkpICsgDQogICAgICAgIGd1aWRlcyhzaGFwZSA9ICJub25lIikNCiAgICBpZiAobG9nX3NjYWxlID09IFRSVUUgJiByYXRpbyA9PSBGQUxTRSkgew0KICAgICAgICBnZyA9IGdnICsgc2NhbGVfeF9sb2cxMCgpICsgc2NhbGVfeV9sb2cxMCgpDQogICAgfQ0KICAgIGlmIChsb2dfc2NhbGUgPT0gVFJVRSAmIHJhdGlvID09IFRSVUUpIHsNCiAgICAgICAgZ2cgPSBnZyArIHNjYWxlX3hfbG9nMTAoKQ0KICAgIH0NCiAgICBpZiAobGFiZWxzID09IFRSVUUpIHsNCiAgICAgICAgZ2cgPSBnZyArIGdncmVwZWw6Omdlb21fbGFiZWxfcmVwZWwoYWVzKGxhYmVsID0gc3BlY2llcyksIA0KICAgICAgICAgICAgYm94LnBhZGRpbmcgPSAwLjM1LCBwb2ludC5wYWRkaW5nID0gMC41LCBzZWdtZW50LmNvbG9yID0gImdyZXk1MCIsIA0KICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwgbWF4Lm92ZXJsYXBzID0gSW5mLCBzZWVkID0gNDIpDQogICAgfQ0KICAgIGdnDQp9DQpgYGANCg0KDQpgYGB7cn0NCnBsb3RCaW9tYXNzT2JzZXJ2ZWRWc01vZGVsQ3VzdG9tKHNpbV9vcHRpbSkNCmBgYA0KDQoNClVzZSB0dW5lUGFyYW1zKCkgdG8gaW52ZXN0aWdhdGUgdGhlIHNwZWNpZXMgd2l0aCBlcmVwcm8gdmFsdWVzIHRvbyBoaWdoDQpgYGB7cn0NCnBhcmFtc190dW5lZF92MDEgPC0gdHVuZVBhcmFtcyhwYXJhbXNfb3B0aW0pDQoNCnBhcmFtc190dW5lZF92MDFAc3BlY2llc19wYXJhbXMkZXJlcHJvDQoNCnBhcmFtc190dW5lZF92MDEgPC0gc3RlYWR5KHBhcmFtc190dW5lZF92MDEpDQpgYGANCg0KYGBge3J9DQojIGNyZWF0ZSBzZXQgb2YgcGFyYW1zIGZvciB0aGUgb3B0aW1pc2F0aW9uIHByb2Nlc3MNCnRpYygpDQoNCnBhcmFtc19vcHRpbSA8LSBwYXJhbXNfdHVuZWRfdjAxDQoNCnZhcnkgPC0gYyhsb2cxMChwYXJhbXNfb3B0aW1Ac3BlY2llc19wYXJhbXMkUl9tYXgpLA0KICAgICAgICAgIHBhcmFtc19vcHRpbUBzcGVjaWVzX3BhcmFtcyRlcmVwcm8sDQogICAgICAgICAgcGFyYW1zX29wdGltQHNwZWNpZXNfcGFyYW1zJGludGVyYWN0aW9uX3Jlc291cmNlKQ0KDQpwYXJhbXNfb3B0aW08LXNldFBhcmFtcyhwYXJhbXNfb3B0aW0pDQoNCiMgc2V0IHVwIHdvcmtlcnMNCm5vQ29yZXMgPC0gcGFyYWxsZWw6OmRldGVjdENvcmVzKCkgLSAxICMga2VlcCBzb21lIHNwYXJlIGNvcmUNCmNsIDwtIHBhcmFsbGVsOjptYWtlQ2x1c3Rlcihub0NvcmVzLCBzZXR1cF90aW1lb3V0ID0gMC41KQ0Kc2V0RGVmYXVsdENsdXN0ZXIoY2wgPSBjbCkNCmNsdXN0ZXJFeHBvcnQoY2wsIHZhcmxpc3QgPSAiY2wiLGVudmlyPWVudmlyb25tZW50KCkpDQpjbHVzdGVyRXZhbFEoY2wsIHsNCiAgbGlicmFyeShtaXplckV4cGVyaW1lbnRhbCkNCiAgbGlicmFyeShvcHRpbVBhcmFsbGVsKQ0KfSkNCg0Kb3B0aW1fcmVzdWx0IDwtIG9wdGltUGFyYWxsZWw6Om9wdGltUGFyYWxsZWwocGFyPXZhcnksZ2V0RXJyb3JDdXN0b20scGFyYW1zPXBhcmFtc19vcHRpbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXQgPSBwYXJhbXNfb3B0aW1Ac3BlY2llc19wYXJhbXMkYmlvbWFzc19vYnNlcnZlZCwgbWV0aG9kID0iTC1CRkdTLUIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyPWMocmVwKC0xNSwxNSkscmVwKDFlLTcsMTUpLHJlcCguMSwxNSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXI9IGMocmVwKDE1LDE1KSxyZXAoMC45OSwxNSkscmVwKC45OSwxNSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYWxsZWw9bGlzdChsb2dpbmZvPVRSVUUsIGZvcndhcmQ9VFJVRSkpDQpzdG9wQ2x1c3RlcihjbCkNCg0KdG9jKCkNCg0Kc2F2ZVJEUyhvcHRpbV9yZXN1bHQsIGZpbGU9Im9wdGltX3Jlc3VsdF92MDEuUkRTIikNCiMgb3B0aW1fcmVzdWx0IDwtIHJlYWRSRFMoIm9wdGltX3Jlc3VsdF92MDAuUkRTIikNCmBgYA0KDQoNCmBgYHtyfQ0KI3B1dCB0aGVzZSBuZXcgdmFscyBpbnRvc3BlY2llc19wYXJhbXMgYW5kIGdvIGJhY2sgdG8gdGhlIHRvcCBvZiB0aGlzIHBhZ2UgdG8gcmUtY2hlY2sgdGhlIGNhbGlicmF0aW9uIA0Kc3BlY2llc19wYXJhbXMocGFyYW1zX29wdGltKSRSX21heDwtMTBeb3B0aW1fcmVzdWx0JHBhclsxOjE1XQ0Kc3BlY2llc19wYXJhbXMocGFyYW1zX29wdGltKSRlcmVwcm88LW9wdGltX3Jlc3VsdCRwYXJbMTY6MzBdDQpzcGVjaWVzX3BhcmFtcyhwYXJhbXNfb3B0aW0pJGludGVyYWN0aW9uX3Jlc291cmNlIDwtb3B0aW1fcmVzdWx0JHBhclszMTo0NV0NCg0Kc3BlY2llc19wYXJhbXMocGFyYW1zX29wdGltKSRSX21heA0Kc3BlY2llc19wYXJhbXMocGFyYW1zX29wdGltKSRlcmVwcm8NCnNwZWNpZXNfcGFyYW1zKHBhcmFtc19vcHRpbSkkaW50ZXJhY3Rpb25fcmVzb3VyY2UNCmBgYA0KDQoNCmBgYHtyfQ0Kc2ltX29wdGltX3YwMiA8LSBwcm9qZWN0KHBhcmFtc19vcHRpbSwgdF9tYXggPSAxMDAwKQ0KcGxvdEJpb21hc3Moc2ltX29wdGltX3YwMikNCmBgYA0KDQpgYGB7cn0NCnBhcmFtc192MDMgPC0gc3RlYWR5KHBhcmFtc19vcHRpbSkNCmBgYA0KDQpgYGB7cn0NCnBhcmFtc19sb29wIDwtIHBhcmFtc192MDMgfD4NCiAgICBtYXRjaEJpb21hc3NlcygpIHw+IHN0ZWFkeSgpIHw+IG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4NCiAgICBtYXRjaEJpb21hc3NlcygpIHw+IHN0ZWFkeSgpIHw+IG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4NCiAgICBtYXRjaEJpb21hc3NlcygpIHw+IHN0ZWFkeSgpIHw+IG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4NCiAgICBtYXRjaEJpb21hc3NlcygpIHw+IHN0ZWFkeSgpIHw+IG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4NCiAgICBtYXRjaEJpb21hc3NlcygpIHw+IHN0ZWFkeSgpIHw+IG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4NCiAgICBtYXRjaEJpb21hc3NlcygpIHw+IHN0ZWFkeSgpIHw+IG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4NCiAgICBtYXRjaEJpb21hc3NlcygpIHw+IHN0ZWFkeSgpIHw+IG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4NCiAgICBtYXRjaEJpb21hc3NlcygpIHw+IHN0ZWFkeSgpIHw+IG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4NCiAgICBtYXRjaEJpb21hc3NlcygpIHw+IHN0ZWFkeSgpIHw+IG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkNCg0KcGFyYW1zX2xvb3BAc3BlY2llc19wYXJhbXMkZXJlcHJvDQpgYGANCg0KYGBge3J9DQpzaW1fdjAyIDwtIHByb2plY3QocGFyYW1zX2xvb3AsIHRfbWF4ID0gMjAwMCkNCmBgYA0KDQoNCg0KYGBge3J9DQpwbG90QmlvbWFzcyhzaW1fdjAyKQ0KcGxvdEJpb21hc3NPYnNlcnZlZFZzTW9kZWxDdXN0b20oc2ltX3YwMikNCnBsb3RCaW9tYXNzT2JzZXJ2ZWRWc01vZGVsKHNpbV92MDIpDQpwbG90RGlldChwYXJhbXNfbG9vcCkNCmBgYA0KU2F2ZSBwcm9ncmVzcw0KYGBge3J9DQojIHNhdmVSRFMocGFyYW1zX2xvb3AsICJwYXJhbXNfb3B0aW1fdjAxLnJkcyIpDQpgYGANCg0KDQpUcnkgdG8gd2VlbiB0aGUgc3BlY2llcyBvZiB0aGUgcmVzb3VyY2Ugc3BlY3RyYQ0KYGBge3J9DQpwYXJhbXNfbG9vcEByZXNvdXJjZV9wYXJhbXMkd19wcF9jdXRvZmYNCnBhcmFtc19sb29wQHJlc291cmNlX3BhcmFtcyRrYXBwYQ0KYGBgDQoNCmBgYHtyfQ0KcmVzb3VyY2VfcGFyYW1zKHBhcmFtc19sb29wKVtbIndfcHBfY3V0b2ZmIl1dIDwtIDEwDQoNCnBhcmFtc192MDQgPC0gc2V0UGFyYW1zKHBhcmFtc19sb29wKQ0KDQpwYXJhbXNfdjA0QHJlc291cmNlX3BhcmFtcyR3X3BwX2N1dG9mZg0KYGBgDQoNCmBgYHtyfQ0Kc2ltX3YwMyA8LSBwcm9qZWN0KHBhcmFtc192MDQsIHRfbWF4ID0gMjAwKQ0KDQpwbG90QmlvbWFzcyhzaW1fdjAzKQ0KcGxvdEJpb21hc3NPYnNlcnZlZFZzTW9kZWxDdXN0b20oc2ltX3YwMykNCnBsb3RCaW9tYXNzT2JzZXJ2ZWRWc01vZGVsKHNpbV92MDMpDQpwbG90RGlldChwYXJhbXNfdjA0KQ0KYGBgDQoNCmBgYHtyfQ0KZ2V0RXJyb3JDdXN0b21fdjAyIDwtIGZ1bmN0aW9uKHZhcnksIHBhcmFtcywgZGF0LCB0b2wgPSAwLjAwMSwgDQogICAgdGltZXRvcnVuID0gMTApDQp7DQogIHBhcmFtc0BzcGVjaWVzX3BhcmFtcyRSX21heFsxOjE1XTwtMTBedmFyeVsxOjE1XSAjIFJfbWF4IGZvciAxNSBzcGVjaWVzDQogIHBhcmFtc0BzcGVjaWVzX3BhcmFtcyRlcmVwcm9bMToxNV08LXZhcnlbMTY6MzBdICMgZXJlcHJvIGZvciAxNSBzcGVjaWVzDQogIHBhcmFtc0BzcGVjaWVzX3BhcmFtcyRpbnRlcmFjdGlvbl9yZXNvdXJjZVsxOjE1XSA8LSB2YXJ5WzMxOjQ1XSAjIGludGVyYWN0aW9uX3Jlc291cmNlIGZvciAxNSBzcGVjaWVzDQogIHBhcmFtc0ByZXNvdXJjZV9wYXJhbXMkd19wcF9jdXRvZmZbMV0gPC0gdmFyeVs0Nl0gIyBpbnRlcmFjdGlvbl9yZXNvdXJjZSBmb3IgMTUgc3BlY2llcw0KICBwYXJhbXMgPC0gc2V0UGFyYW1zKHBhcmFtcykNCiAgIyBpbnRlcmFjdGlvbiA8LSBwYXJhbXNAaW50ZXJhY3Rpb24NCiAgIyBpbnRlcmFjdGlvbltdIDwtIG1hdHJpeCh2YXJ5WzI4OjEwOF0sbnJvdyA9IDkpICMgc3RvcCBhdCA1NCBpZiBsb29raW5nIG9ubHkgYXQgMyBiaWdnZXN0IHNwZWNpZXMNCiAgDQogICMgcGFyYW1zIDwtIHNldEludGVyYWN0aW9uKHBhcmFtcyxpbnRlcmFjdGlvbikNCiAgICBwYXJhbXMgPC0gcHJvamVjdFRvU3RlYWR5KHBhcmFtcywgZGlzdGFuY2VfZnVuYyA9IGRpc3RhbmNlU1NMb2dOLCANCiAgICAgICAgdG9sID0gdG9sLCB0X21heCA9IDIwMCwgcmV0dXJuX3NpbSA9IEYpDQogICAgDQogICAgc2ltIDwtIHByb2plY3QocGFyYW1zLCB0X21heCA9IHRpbWV0b3J1biwgcHJvZ3Jlc3NfYmFyID0gRikNCiAgICANCiAgICBzaW1fYmlvbWFzcyA9IHJlcCgwLCBsZW5ndGgocGFyYW1zQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMpKQ0KICAgIA0KICAgICAgICBjdXRvZmZMb3cgPC0gcGFyYW1zQHNwZWNpZXNfcGFyYW1zJGJpb21hc3NfY3V0b2ZmTG93DQogICAgaWYgKGlzLm51bGwoY3V0b2ZmTG93KSkgDQogICAgICAgIGN1dG9mZkxvdyA8LSByZXAoMCwgbm9fc3ApDQogICAgY3V0b2ZmTG93W2lzLm5hKGN1dG9mZkxvdyldIDwtIDANCiAgICANCiAgICAgICAgY3V0b2ZmSGlnaCA8LSBwYXJhbXNAc3BlY2llc19wYXJhbXMkYmlvbWFzc19jdXRvZmZIaWdoDQogICAgaWYgKGlzLm51bGwoY3V0b2ZmSGlnaCkpIA0KICAgICAgICBjdXRvZmZIaWdoIDwtIHJlcCgwLCBub19zcCkNCiAgICBjdXRvZmZIaWdoW2lzLm5hKGN1dG9mZkhpZ2gpXSA8LSAwDQogICAgICAgIA0KICAgIGZvciAoaiBpbiAxOmxlbmd0aChzaW1fYmlvbWFzcykpIHsNCiAgICAgICAgc2ltX2Jpb21hc3Nbal0gPSBzdW0oKHNpbUBuW2RpbShzaW1AbilbMV0saixdICogcGFyYW1zQHcgKiANCiAgICAgICAgICAgIHBhcmFtc0BkdylbcGFyYW1zQHcgPj0gY3V0b2ZmTG93W2pdICYgY3V0b2ZmSGlnaFtqXSA+PSBwYXJhbXNAd10pDQogICAgfQ0KICAgIA0KICAgICBwcmVkIDwtIGxvZyhzaW1fYmlvbWFzcykNCiAgICBkYXQgPC0gbG9nKGRhdCkNCiAgICBkaXNjcmVwIDwtIHByZWQgLSBkYXQNCiAgICBkaXNjcmVwIDwtIChzdW0oZGlzY3JlcF4yKSkNCiAgICByZXR1cm4oZGlzY3JlcCkNCn0NCiAgICANCmBgYA0KDQoNCmBgYHtyfQ0KIyBjcmVhdGUgc2V0IG9mIHBhcmFtcyBmb3IgdGhlIG9wdGltaXNhdGlvbiBwcm9jZXNzDQp0aWMoKQ0KDQpwYXJhbXNfb3B0aW0gPC0gcGFyYW1zX3YwNA0KDQp2YXJ5IDwtIGMobG9nMTAocGFyYW1zX29wdGltQHNwZWNpZXNfcGFyYW1zJFJfbWF4KSwNCiAgICAgICAgICBwYXJhbXNfb3B0aW1Ac3BlY2llc19wYXJhbXMkZXJlcHJvLA0KICAgICAgICAgIHBhcmFtc19vcHRpbUBzcGVjaWVzX3BhcmFtcyRpbnRlcmFjdGlvbl9yZXNvdXJjZSwNCiAgICAgICAgICBwYXJhbXNfb3B0aW1AcmVzb3VyY2VfcGFyYW1zJHdfcHBfY3V0b2ZmKQ0KDQpwYXJhbXNfb3B0aW08LXNldFBhcmFtcyhwYXJhbXNfb3B0aW0pDQoNCiMgc2V0IHVwIHdvcmtlcnMNCm5vQ29yZXMgPC0gcGFyYWxsZWw6OmRldGVjdENvcmVzKCkgLSAxICMga2VlcCBzb21lIHNwYXJlIGNvcmUNCmNsIDwtIHBhcmFsbGVsOjptYWtlQ2x1c3Rlcihub0NvcmVzLCBzZXR1cF90aW1lb3V0ID0gMC41KQ0Kc2V0RGVmYXVsdENsdXN0ZXIoY2wgPSBjbCkNCmNsdXN0ZXJFeHBvcnQoY2wsIHZhcmxpc3QgPSAiY2wiLGVudmlyPWVudmlyb25tZW50KCkpDQpjbHVzdGVyRXZhbFEoY2wsIHsNCiAgbGlicmFyeShtaXplckV4cGVyaW1lbnRhbCkNCiAgbGlicmFyeShvcHRpbVBhcmFsbGVsKQ0KfSkNCg0Kb3B0aW1fcmVzdWx0IDwtIG9wdGltUGFyYWxsZWw6Om9wdGltUGFyYWxsZWwocGFyPXZhcnksZ2V0RXJyb3JDdXN0b21fdjAyLHBhcmFtcz1wYXJhbXNfb3B0aW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0ID0gcGFyYW1zX29wdGltQHNwZWNpZXNfcGFyYW1zJGJpb21hc3Nfb2JzZXJ2ZWQsIG1ldGhvZCA9IkwtQkZHUy1CIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlcj1jKHJlcCgtMTUsMTUpLHJlcCgxZS03LDE1KSxyZXAoLjEsMTUpLCAwLjEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXI9IGMocmVwKDE1LDE1KSxyZXAoMC45OSwxNSkscmVwKC45OSwxNSksMTAwMCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbD1saXN0KGxvZ2luZm89VFJVRSwgZm9yd2FyZD1UUlVFKSkNCnN0b3BDbHVzdGVyKGNsKQ0KDQp0b2MoKQ0KDQpzYXZlUkRTKG9wdGltX3Jlc3VsdCwgZmlsZT0ib3B0aW1fcmVzdWx0X3YwMi5SRFMiKQ0KIyBvcHRpbV9yZXN1bHQgPC0gcmVhZFJEUygib3B0aW1fcmVzdWx0X3YwMC5SRFMiKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCiNwdXQgdGhlc2UgbmV3IHZhbHMgaW50b3NwZWNpZXNfcGFyYW1zIGFuZCBnbyBiYWNrIHRvIHRoZSB0b3Agb2YgdGhpcyBwYWdlIHRvIHJlLWNoZWNrIHRoZSBjYWxpYnJhdGlvbiANCnNwZWNpZXNfcGFyYW1zKHBhcmFtc19vcHRpbSkkUl9tYXg8LTEwXm9wdGltX3Jlc3VsdCRwYXJbMToxNV0NCnNwZWNpZXNfcGFyYW1zKHBhcmFtc19vcHRpbSkkZXJlcHJvPC1vcHRpbV9yZXN1bHQkcGFyWzE2OjMwXQ0Kc3BlY2llc19wYXJhbXMocGFyYW1zX29wdGltKSRpbnRlcmFjdGlvbl9yZXNvdXJjZSA8LW9wdGltX3Jlc3VsdCRwYXJbMzE6NDVdDQpyZXNvdXJjZV9wYXJhbXMocGFyYW1zX29wdGltKSR3X3BwX2N1dG9mZiA8LSBvcHRpbV9yZXN1bHQkcGFyWzQ2XQ0KDQpzcGVjaWVzX3BhcmFtcyhwYXJhbXNfb3B0aW0pJFJfbWF4DQpzcGVjaWVzX3BhcmFtcyhwYXJhbXNfb3B0aW0pJGVyZXBybw0Kc3BlY2llc19wYXJhbXMocGFyYW1zX29wdGltKSRpbnRlcmFjdGlvbl9yZXNvdXJjZQ0KYGBgDQoNCg0KYGBge3J9DQpzaW1fdjA0IDwtIHByb2plY3QocGFyYW1zX29wdGltLCB0X21heCA9IDEwMDApDQoNCnBsb3RCaW9tYXNzKHNpbV92MDQpDQpwbG90QmlvbWFzc09ic2VydmVkVnNNb2RlbEN1c3RvbShzaW1fdjA0KQ0KcGxvdEJpb21hc3NPYnNlcnZlZFZzTW9kZWwoc2ltX3YwNCkNCnBsb3REaWV0KHBhcmFtc19vcHRpbSkNCmBgYA0KDQpgYGB7cn0NCnBhcmFtc19zdGVhZHkgPC0gcGFyYW1zX29wdGltDQoNCmluaXRpYWxOKHBhcmFtc19zdGVhZHkpIDwtIHNpbV92MDRAbltkaW0oc2ltX3YwNEBuKVsxXSwsXQ0KDQpwbG90RGlldChwYXJhbXNfc3RlYWR5KQ0KDQpzaW1fdjA1IDwtIHByb2plY3QocGFyYW1zX3N0ZWFkeSwgdF9tYXggPSAxMDApDQoNCnBsb3RCaW9tYXNzKHNpbV92MDUpDQoNCnBsb3RHcm93dGhDdXJ2ZXMoc2ltX3YwNSwgc3BlY2llc19wYW5lbCA9IFQpDQpgYGANCg0KYGBge3J9DQpwYXJhbXNfdHVuZWRfdjAyIDwtIHR1bmVQYXJhbXMocGFyYW1zX3N0ZWFkeSkNCg0KcGFyYW1zX3R1bmVkX3YwMiA8LSBzdGVhZHkocGFyYW1zX3R1bmVkX3YwMikNCg0KcGFyYW1zX3R1bmVkX3YwMkBzcGVjaWVzX3BhcmFtcyRlcmVwcm8NCmBgYA0Kc3BlY2llcyAgICAgICAgd19taW4gICAgIHdfbWF0ICAgIHdfbWF4IGJldGEga192YiAgaCBtaW5fZGVwdGggbWF4X2RlcHRoIHdhdGVyLmNvbHVtbi51c2UgcF90aW1lX3ByeWR6IHBjX2FubnVhbF9vZmZzcHJpbmcNCjUgICBzYWxwcyAzLjE2MjI3OGUtMDUgMC4yNTExODg2IDI1LjExODg2IDEwMDAgICBOQSAzMyAgICAgICAgIDAgICAgICAgNTAwICAgICAgICAgIG5vbiBEVk0gICAgICAgICAgICAxICAgICAgICAgICAgICAgICAgTkENCiAgYmlvbWFzc19vYnNlcnZlZA0KNSAgICAgICAgICAgIDAuNjUyDQpgYGB7cn0NCnNwZWNpZXNfcGFyYW1zIDwtIGRhdGEuZnJhbWUoDQogICAgc3BlY2llcyA9ICJzYWxwcyIsDQogICAgd19taW4gPSAzLjE2MjI3OGUtMDUsDQogICAgd19tYXggPSAyNS4xMTg4NiwNCiAgICB3X21hdCA9IDAuMjUxMTg4NiwNCiAgICBiZXRhID0gMTAwMDAwMCwNCiAgICBzaWdtYSA9IDIsDQogICAgYmlvbWFzc19vYnNlcnZlZCA9IDAuNjUyLA0KICAgIGtfdmIgPSAwLjQsDQogICAgeWllbGRfb2JzZXJ2ZWQgPSAwLA0KICAgIGJpb21hc3NfY3V0b2ZmID0gMC4xLA0KICAgIGJpb21hc3NfY3V0b2ZmTG93ID0gMC4xLA0KICAgIGJpb21hc3NfY3V0b2ZmSGlnaCA9IDI1LjExODg2DQopDQoNCnBhcmFtc192MDUgPC0gYWRkU3BlY2llcyhwYXJhbXNfdHVuZWRfdjAyLCBzcGVjaWVzX3BhcmFtcykNCnBsb3RTcGVjdHJhKHBhcmFtc192MDUpDQoNCnBhcmFtc192MDVAc3BlY2llc19wYXJhbXMkZXJlcHJvDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBmdW5jdGlvbiBydW5uaW5nIHR1bmVQYXJhbXMgZnVuY3Rpb24gaW4gYSByb3cgZm9yIGEgcXVpY2sgc3RhcnQgdG8gYSBjYWxpYnJhdGlvbg0KZmFzdENhbGliIDwtIGZ1bmN0aW9uKHBhcmFtcywgbWF0Y2ggPSBGKQ0Kew0KcGFyYW1zIDwtIGNhbGlicmF0ZUJpb21hc3MocGFyYW1zKSAjIGNoYW5nZXMga2FwcGEgYW5kIHJtYXgNCmlmKG1hdGNoKSBwYXJhbXMgPC0gbWF0Y2hCaW9tYXNzZXMocGFyYW1zKSAjIHNldCBybWF4IHRvIGluZiBhbmQgYWRqdXN0IGVyZXBybw0KcGFyYW1zIDwtIHN0ZWFkeShwYXJhbXMsIHRvbCA9IDAuMDAxKQ0Kc2ltIDwtIHByb2plY3QocGFyYW1zLCB0X21heCA9IDEwMDApDQpyZXR1cm4oc2ltKQ0KfQ0KYGBgDQoNCg0KYGBge3J9DQpzaW1fdjA2IDwtIGZhc3RDYWxpYihwYXJhbXNfdjA1KQ0KDQpwbG90QmlvbWFzcyhzaW1fdjA2KQ0KcGxvdERpZXQocGFyYW1zX3YwNSkNCmBgYA0KDQpgYGB7cn0NCnNvX3RoZXRhIDwtIGFzLm1hdHJpeChwYXJhbXNfdjA1QGludGVyYWN0aW9uKQ0KDQpzYWxwX3JvdyA8LSBjKDEsDQowLjEyNTAwMDAsDQowLjEyNTAwMDAsDQowLjEzNzM2MjYsDQowLjA1MDAwMDAsDQowLjEwMDAwMDAsDQowLjI1MDAwMDAsDQowLjI1MDAwMDAsDQowLjEwMDAwMDAsDQowLjE2NjY2NjcsDQowLjE2NjY2NjcsDQowLjA1MDAwMDAsDQowLjIwMDAwMDAsDQowLjEyNTAwMDAsDQowLjIwMDAwMDAsDQoxKQ0KYGBgDQoNCg0KYGBge3J9DQpzb190aGV0YVsxNixdICMgYXV0b21hdGVkIHNhbHBzIGludGVyYWN0aW9uIHdoZW4gYWRkZWQgdXNpbmcgYWRkU3BlY2llcygpDQoNCnNvX3RoZXRhWzE2LF0gPC0gc2FscF9yb3cNCg0Kc29fdGhldGFbLDE2XSAjIGF1dG9tYXRlZCBzYWxwcyBpbnRlcmFjdGlvbiB3aGVuIGFkZGVkIHVzaW5nIGFkZFNwZWNpZXMoKQ0KDQpzb190aGV0YVssMTZdIDwtIHNhbHBfcm93DQoNCnNvX3RoZXRhDQpgYGANCg0KDQpgYGB7cn0NCnBhcmFtc192MDYgPC0gc2V0UGFyYW1zKHBhcmFtc192MDUsIGludGVyYWN0aW9uID0gc29fdGhldGEpDQoNCnBhcmFtc192MDZAaW50ZXJhY3Rpb24NCmBgYA0KDQoNCmBgYHtyfQ0Kc2ltX3YwNyA8LSBmYXN0Q2FsaWIocGFyYW1zX3YwNikNCg0KcGxvdEJpb21hc3Moc2ltX3YwNykNCmBgYA0KDQpgYGB7cn0NCmluaXRpYWxOKHBhcmFtc192MDYpIDwtIHNpbV92MDdAbltkaW0oc2ltX3YwN0BuKVsxXSwsXQ0KYGBgDQoNCg0KYGBge3J9DQpzaW1fdjA4IDwtIHByb2plY3QocGFyYW1zX3YwNiwgdF9tYXggPSAxMDApDQpwbG90QmlvbWFzcyhzaW1fdjA4KQ0KcGxvdERpZXQocGFyYW1zX3YwNikNCmBgYA0KDQpGaWxsIGluIG1pc3NpbmcgYW5kIGFkanVzdCBiZXRhIHZhbHVlcyBmb3Igem9vcGxhbmt0b24gZ3JvdXBzIHVzaW5nIEhlbmVnaGFuIGV0IGFsLiAyMDIwICgxMC4xMDE2L2ouZWNvbG1vZGVsLjIwMjAuMTA5MjY1KQ0KDQpOZWVkIGEgdmFsdWUgZm9yIG1pY3Jvem9vcGxhbmt0b24NCm1pY3Jvem9vcGxhbmt0b24gKGluIE1jQ29ybWFjayBldCBhbC4gMjAyMCkgaXMgY29tcG9zZWQgb2YgSGV0ZXJvdHJvcGhpYyBkaW5vZmxhZ2VsbGF0ZXMsIHRpbnRpbm5pZHMsIGNpbGlhdGVzLCBjb3BlcG9kIG5hdXBsaWkNCkhlbmVnaGFuIGV0IGFsLiBsb2cxMFBQTVIgdmFsdWVzIGZvcjoNCkhldGVyby5GbGFnZWxsYXRlcyA9IDAuMuKAkzAuNzIgLT4gMC40Ng0KSGV0ZXJvLkNpbGlhdGVzID0gMi414oCTMi45IC0+IDIuNw0KTWVhbjogKDIuNyswLjQ2KS8yID0gMS41OA0KMTBeMS41OCA9IDM4LjAxODk0DQoNCk5lZWQgdG8gYWRqdXN0IHZhbHVlcyBmb3IgbWVzb3pvbywgb3RoZXIgbWFjcm96b28sIGV1cGhhdXNpaWRzLCBzYWxwcw0KDQpIZW5lZ2hhbiBldCBhbC4gbG9nMTBQUE1SIHZhbHVlcyAobWlkcG9pbnRzIGZvciByYW5nZSkgZm9yOg0Kc2FscHMgPSA2LjjigJMxMS43IC0+IDkuMjUNCjEwXjkuMjUgPSAxNzc4Mjc5NDEwDQoNCmV1cGhhdXNpaWRzID0gNi424oCTNy44IC0+IDcuMg0KMTBeNy4yID0gMTU4NDg5MzINCg0KbWVzb3pvbyAoY29wZXBvZHMpDQpPbW5pLkNvcC4gPSAzLjbigJM0LjYgLT4gNC4xDQpDYXJuLkNvcC4gPSAwLjjigJMxLjkgLT4gMS4zNQ0KTWVhbjogKDQuMSsxLjM1KS8yID0gMi43MjUNCjEwXjIuNzI1ID0gNTMwLjg4NDQNCg0Kb3RoZXIgbWFjcm96b28gKCkNCkNoYWV0b2duYXRocyA9IDEuOeKAkzMuNCAtPiAyLjY1DQoxMF4yLjY1ID0gNDQ2LjY4MzYNCg0KYGBge3J9DQpwYXJhbXNfdHVuZWRfdjAzIDwtIHR1bmVQYXJhbXMocGFyYW1zX3YwNikNCnBhcmFtc190dW5lZF92MDQgPC0gdHVuZVBhcmFtcyhwYXJhbXNfdHVuZWRfdjAzKSAjIHVwZGF0ZWQgc2FscHMgUFBNUiB0byBtYXRjaCBlbXBpcmljYWwgZXN0aW1hdGVzIGZyb20gSGVuZWdoYW4gZXQgYWwgMjAyMA0KYGBgDQoNCg0KYGBge3J9DQpnZXRFcnJvckN1c3RvbV92MyA8LSBmdW5jdGlvbih2YXJ5LCBwYXJhbXMsIGRhdCwgdG9sID0gMC4wMDEsIA0KICAgIHRpbWV0b3J1biA9IDEwKQ0Kew0KICBwYXJhbXNAc3BlY2llc19wYXJhbXMkUl9tYXhbMToxNl08LTEwXnZhcnlbMToxNl0gIyBSX21heCBmb3IgMTUgc3BlY2llcw0KICBwYXJhbXNAc3BlY2llc19wYXJhbXMkZXJlcHJvWzE6MTZdPC12YXJ5WzE3OjMyXSAjIGVyZXBybyBmb3IgMTUgc3BlY2llcw0KICBwYXJhbXNAc3BlY2llc19wYXJhbXMkaW50ZXJhY3Rpb25fcmVzb3VyY2VbMToxNl0gPC0gdmFyeVszMzo0OF0gIyBpbnRlcmFjdGlvbl9yZXNvdXJjZSBmb3IgMTUgc3BlY2llcw0KICBwYXJhbXMgPC0gc2V0UGFyYW1zKHBhcmFtcykNCiAgIyBpbnRlcmFjdGlvbiA8LSBwYXJhbXNAaW50ZXJhY3Rpb24NCiAgIyBpbnRlcmFjdGlvbltdIDwtIG1hdHJpeCh2YXJ5WzI4OjEwOF0sbnJvdyA9IDkpICMgc3RvcCBhdCA1NCBpZiBsb29raW5nIG9ubHkgYXQgMyBiaWdnZXN0IHNwZWNpZXMNCiAgDQogICMgcGFyYW1zIDwtIHNldEludGVyYWN0aW9uKHBhcmFtcyxpbnRlcmFjdGlvbikNCiAgICBwYXJhbXMgPC0gcHJvamVjdFRvU3RlYWR5KHBhcmFtcywgZGlzdGFuY2VfZnVuYyA9IGRpc3RhbmNlU1NMb2dOLCANCiAgICAgICAgdG9sID0gdG9sLCB0X21heCA9IDIwMCwgcmV0dXJuX3NpbSA9IEYpDQogICAgDQogICAgc2ltIDwtIHByb2plY3QocGFyYW1zLCB0X21heCA9IHRpbWV0b3J1biwgcHJvZ3Jlc3NfYmFyID0gRikNCiAgICANCiAgICBzaW1fYmlvbWFzcyA9IHJlcCgwLCBsZW5ndGgocGFyYW1zQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMpKQ0KICAgIA0KICAgICAgICBjdXRvZmZMb3cgPC0gcGFyYW1zQHNwZWNpZXNfcGFyYW1zJGJpb21hc3NfY3V0b2ZmTG93DQogICAgaWYgKGlzLm51bGwoY3V0b2ZmTG93KSkgDQogICAgICAgIGN1dG9mZkxvdyA8LSByZXAoMCwgbm9fc3ApDQogICAgY3V0b2ZmTG93W2lzLm5hKGN1dG9mZkxvdyldIDwtIDANCiAgICANCiAgICAgICAgY3V0b2ZmSGlnaCA8LSBwYXJhbXNAc3BlY2llc19wYXJhbXMkYmlvbWFzc19jdXRvZmZIaWdoDQogICAgaWYgKGlzLm51bGwoY3V0b2ZmSGlnaCkpIA0KICAgICAgICBjdXRvZmZIaWdoIDwtIHJlcCgwLCBub19zcCkNCiAgICBjdXRvZmZIaWdoW2lzLm5hKGN1dG9mZkhpZ2gpXSA8LSAwDQogICAgICAgIA0KICAgIGZvciAoaiBpbiAxOmxlbmd0aChzaW1fYmlvbWFzcykpIHsNCiAgICAgICAgc2ltX2Jpb21hc3Nbal0gPSBzdW0oKHNpbUBuW2RpbShzaW1AbilbMV0saixdICogcGFyYW1zQHcgKiANCiAgICAgICAgICAgIHBhcmFtc0BkdylbcGFyYW1zQHcgPj0gY3V0b2ZmTG93W2pdICYgY3V0b2ZmSGlnaFtqXSA+PSBwYXJhbXNAd10pDQogICAgfQ0KICAgIA0KICAgICBwcmVkIDwtIGxvZyhzaW1fYmlvbWFzcykNCiAgICBkYXQgPC0gbG9nKGRhdCkNCiAgICBkaXNjcmVwIDwtIHByZWQgLSBkYXQNCiAgICBkaXNjcmVwIDwtIChzdW0oZGlzY3JlcF4yKSkNCiAgICByZXR1cm4oZGlzY3JlcCkNCn0NCmBgYA0KDQoNCg0KDQpgYGB7cn0NCiMgY3JlYXRlIHNldCBvZiBwYXJhbXMgZm9yIHRoZSBvcHRpbWlzYXRpb24gcHJvY2Vzcw0KdGljKCkNCg0KcGFyYW1zX29wdGltIDwtIHBhcmFtc190dW5lZF92MDQNCg0KdmFyeSA8LSBjKGxvZzEwKHBhcmFtc19vcHRpbUBzcGVjaWVzX3BhcmFtcyRSX21heCksDQogICAgICAgICAgcGFyYW1zX29wdGltQHNwZWNpZXNfcGFyYW1zJGVyZXBybywNCiAgICAgICAgICBwYXJhbXNfb3B0aW1Ac3BlY2llc19wYXJhbXMkaW50ZXJhY3Rpb25fcmVzb3VyY2UpDQoNCnBhcmFtc19vcHRpbTwtc2V0UGFyYW1zKHBhcmFtc19vcHRpbSkNCg0KIyBzZXQgdXAgd29ya2Vycw0Kbm9Db3JlcyA8LSBwYXJhbGxlbDo6ZGV0ZWN0Q29yZXMoKSAtIDEgIyBrZWVwIHNvbWUgc3BhcmUgY29yZQ0KY2wgPC0gcGFyYWxsZWw6Om1ha2VDbHVzdGVyKG5vQ29yZXMsIHNldHVwX3RpbWVvdXQgPSAwLjUpDQpzZXREZWZhdWx0Q2x1c3RlcihjbCA9IGNsKQ0KY2x1c3RlckV4cG9ydChjbCwgdmFybGlzdCA9ICJjbCIsZW52aXI9ZW52aXJvbm1lbnQoKSkNCmNsdXN0ZXJFdmFsUShjbCwgew0KICBsaWJyYXJ5KG1pemVyRXhwZXJpbWVudGFsKQ0KICBsaWJyYXJ5KG9wdGltUGFyYWxsZWwpDQp9KQ0KDQpvcHRpbV9yZXN1bHQgPC0gb3B0aW1QYXJhbGxlbDo6b3B0aW1QYXJhbGxlbChwYXI9dmFyeSxnZXRFcnJvckN1c3RvbV92MyxwYXJhbXM9cGFyYW1zX29wdGltLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdCA9IHBhcmFtc19vcHRpbUBzcGVjaWVzX3BhcmFtcyRiaW9tYXNzX29ic2VydmVkLCBtZXRob2QgPSJMLUJGR1MtQiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXI9YyhyZXAoLTE1LDE2KSxyZXAoMWUtNywxNikscmVwKC4xLDE2KSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlcj0gYyhyZXAoMTUsMTYpLHJlcCgwLjk5LDE2KSxyZXAoLjk5LDE2KSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbD1saXN0KGxvZ2luZm89VFJVRSwgZm9yd2FyZD1UUlVFKSkNCnN0b3BDbHVzdGVyKGNsKQ0KDQp0b2MoKQ0KDQpzYXZlUkRTKG9wdGltX3Jlc3VsdCwgZmlsZT0ib3B0aW1fcmVzdWx0X3YwMy5SRFMiKQ0KIyBvcHRpbV9yZXN1bHQgPC0gcmVhZFJEUygib3B0aW1fcmVzdWx0X3YwMC5SRFMiKQ0KYGBgDQoNCg0KYGBge3J9DQojcHV0IHRoZXNlIG5ldyB2YWxzIGludG9zcGVjaWVzX3BhcmFtcyBhbmQgZ28gYmFjayB0byB0aGUgdG9wIG9mIHRoaXMgcGFnZSB0byByZS1jaGVjayB0aGUgY2FsaWJyYXRpb24gDQpzcGVjaWVzX3BhcmFtcyhwYXJhbXNfb3B0aW0pJFJfbWF4PC0xMF5vcHRpbV9yZXN1bHQkcGFyWzE6MTZdDQpzcGVjaWVzX3BhcmFtcyhwYXJhbXNfb3B0aW0pJGVyZXBybzwtb3B0aW1fcmVzdWx0JHBhclsxNzozMl0NCnNwZWNpZXNfcGFyYW1zKHBhcmFtc19vcHRpbSkkaW50ZXJhY3Rpb25fcmVzb3VyY2UgPC1vcHRpbV9yZXN1bHQkcGFyWzMzOjQ4XQ0KDQpzcGVjaWVzX3BhcmFtcyhwYXJhbXNfb3B0aW0pJFJfbWF4DQpzcGVjaWVzX3BhcmFtcyhwYXJhbXNfb3B0aW0pJGVyZXBybw0Kc3BlY2llc19wYXJhbXMocGFyYW1zX29wdGltKSRpbnRlcmFjdGlvbl9yZXNvdXJjZQ0KYGBgDQoNCmBgYHtyfQ0Kc2ltX3YwOSA8LSBwcm9qZWN0KHBhcmFtc19vcHRpbSwgdF9tYXggPSAyMDApDQpwbG90QmlvbWFzcyhzaW1fdjA5KQ0KYGBgDQoNCg0KYGBge3J9DQpwYXJhbXNfdjA3IDwtIHBhcmFtc19vcHRpbQ0KaW5pdGlhbE4ocGFyYW1zX3YwNykgPC0gc2ltX3YwOUBuW2RpbShzaW1fdjA5QG4pWzFdLCxdDQpgYGANCg0KDQpgYGB7cn0NCnNpbV92MTAgPC0gcHJvamVjdChwYXJhbXNfdjA3LCB0X21heCA9IDIwMCkNCnBsb3RCaW9tYXNzKHNpbV92MTApDQpwbG90RGlldChwYXJhbXNfdjA3KQ0KYGBgDQoNCmBgYHtyfQ0KaW5pdGlhbE4ocGFyYW1zX3YwNykgPC0gc2ltX3YxMEBuW2RpbShzaW1fdjEwQG4pWzFdLCxdDQpgYGANCg0KDQoNCmBgYHtyfQ0Kc2ltX3YxMSA8LSBwcm9qZWN0KHBhcmFtc192MDcsIHRfbWF4ID0gMjAwKQ0KcGxvdEJpb21hc3Moc2ltX3YxMSkNCmBgYA0KDQoNCmBgYHtyfQ0KcGFyYW1zX3R1bmVkX3YwNSA8LSB0dW5lUGFyYW1zKHBhcmFtc192MDcpDQoNCnBhcmFtc190dW5lZF92MDUgPC0gc3RlYWR5KHBhcmFtc190dW5lZF92MDUpDQoNCnBhcmFtc190dW5lZF92MDVAc3BlY2llc19wYXJhbXMkZXJlcHJvDQpgYGANCg0KDQpgYGB7cn0NCiMgc2F2ZVJEUyhwYXJhbXNfdHVuZWRfdjA1LCAicGFyYW1zX29wdGltX3YwMi5yZHMiKQ0KDQpwYXJhbXNfdHVuZWRfdjA1IDwtIHJlYWRSRFMoInBhcmFtc19vcHRpbV92MDIucmRzIikNCmBgYA0KDQoNCg0KYGBge3J9DQpzaW1fdjEyIDwtIHByb2plY3QocGFyYW1zX3R1bmVkX3YwNSwgdF9tYXggPSA1MDApDQoNCmluaXRpYWxOKHBhcmFtc190dW5lZF92MDUpIDwtIHNpbV92MTJAbltkaW0oc2ltX3YxMkBuKVsxXSwsXQ0KDQpzaW1fdjEzIDwtIHByb2plY3QocGFyYW1zX3R1bmVkX3YwNSwgdF9tYXggPSA1MDApDQpgYGANCg0KYGBge3J9DQpwbG90bHlCaW9tYXNzKHNpbV92MTMpDQpwbG90QmlvbWFzc09ic2VydmVkVnNNb2RlbChzaW1fdjEzKQ0KcGxvdEJpb21hc3NPYnNlcnZlZFZzTW9kZWxDdXN0b20oc2ltX3YxMykNCmBgYA0KDQpHcmFkdWFsbHkgcmVkdWNpbmcgcmVzb3VyY2UgbWF4aW11bSBzaXplIGluIHR1bmVQYXJhbXMoKSwgYXMgZG9pbmcgaXQgZGlyZWN0bHkgaW4gdGhlIHNldFBhcmFtcygpIHJvdXRlIHdpbGwgdGVsbCB5b3UgdGhlIHdfcHBfY3V0b2ZmIGhhcyBjaGFuZ2VkLCBidXQgaXQgd2lsbCBzdGlsbCBpbmNvcnBvcmF0ZSBhIGJhY2tncm91bmQgcmVzb3VyY2UgdXAgdG8gdGhlIHdfcHBfY3V0b2ZmIHRoYXQgd2FzIG9yaWdpbmFsbHkgdXNlZCBpbiBuZXdNdWx0aXNwZWNpZXNQYXJhbXMoKQ0KDQpgYGB7cn0NCnBhcmFtc190dW5lZF92MDYgPC0gdHVuZVBhcmFtcyhwYXJhbXNfdHVuZWRfdjA1KQ0KDQpwYXJhbXNfdHVuZWRfdjA2IDwtIHN0ZWFkeShwYXJhbXNfdHVuZWRfdjA2KQ0KDQpwYXJhbXNfdHVuZWRfdjA2QHNwZWNpZXNfcGFyYW1zJGVyZXBybw0KcGFyYW1zX3R1bmVkX3YwNkBzcGVjaWVzX3BhcmFtcyRSX21heA0KDQpgYGANCmBgYHtyfQ0KcGFyYW1zX3R1bmVkX3YxMCA8LSB0dW5lUGFyYW1zKHBhcmFtc190dW5lZF92MDYpDQoNCnBhcmFtc190dW5lZF92MTAgPC0gc3RlYWR5KHBhcmFtc190dW5lZF92MTApDQoNCnBhcmFtc190dW5lZF92MTBAc3BlY2llc19wYXJhbXMkZXJlcHJvDQpwYXJhbXNfdHVuZWRfdjEwQHNwZWNpZXNfcGFyYW1zJFJfbWF4DQoNCnBhcmFtc190dW5lZF92MTBAcmVzb3VyY2VfcGFyYW1zJHdfcHBfY3V0b2ZmDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBzYXZlUkRTKHBhcmFtc190dW5lZF92MDYsICJwYXJhbXNfb3B0aW1fdjAyX3dfcHBfMTAwLnJkcyIpDQojIHNhdmVSRFMocGFyYW1zX3R1bmVkX3YxMCwgInBhcmFtc19vcHRpbV92MDNfd19wcF8xMDAucmRzIikNCg0KYGBgDQoNCg0KYGBge3J9DQojIGNyZWF0ZSBzZXQgb2YgcGFyYW1zIGZvciB0aGUgb3B0aW1pc2F0aW9uIHByb2Nlc3MNCnRpYygpDQoNCnBhcmFtc19vcHRpbSA8LSBwYXJhbXNfdHVuZWRfdjEwDQoNCnZhcnkgPC0gYyhsb2cxMChwYXJhbXNfb3B0aW1Ac3BlY2llc19wYXJhbXMkUl9tYXgpLA0KICAgICAgICAgIHBhcmFtc19vcHRpbUBzcGVjaWVzX3BhcmFtcyRlcmVwcm8sDQogICAgICAgICAgcGFyYW1zX29wdGltQHNwZWNpZXNfcGFyYW1zJGludGVyYWN0aW9uX3Jlc291cmNlKQ0KDQpwYXJhbXNfb3B0aW08LXNldFBhcmFtcyhwYXJhbXNfb3B0aW0pDQoNCiMgc2V0IHVwIHdvcmtlcnMNCm5vQ29yZXMgPC0gcGFyYWxsZWw6OmRldGVjdENvcmVzKCkgLSAxICMga2VlcCBzb21lIHNwYXJlIGNvcmUNCmNsIDwtIHBhcmFsbGVsOjptYWtlQ2x1c3Rlcihub0NvcmVzLCBzZXR1cF90aW1lb3V0ID0gMC41KQ0Kc2V0RGVmYXVsdENsdXN0ZXIoY2wgPSBjbCkNCmNsdXN0ZXJFeHBvcnQoY2wsIHZhcmxpc3QgPSAiY2wiLGVudmlyPWVudmlyb25tZW50KCkpDQpjbHVzdGVyRXZhbFEoY2wsIHsNCiAgbGlicmFyeShtaXplckV4cGVyaW1lbnRhbCkNCiAgbGlicmFyeShvcHRpbVBhcmFsbGVsKQ0KfSkNCg0Kb3B0aW1fcmVzdWx0IDwtIG9wdGltUGFyYWxsZWw6Om9wdGltUGFyYWxsZWwocGFyPXZhcnksZ2V0RXJyb3JDdXN0b21fdjMscGFyYW1zPXBhcmFtc19vcHRpbSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdCA9IHBhcmFtc19vcHRpbUBzcGVjaWVzX3BhcmFtcyRiaW9tYXNzX29ic2VydmVkLCBtZXRob2QgPSJMLUJGR1MtQiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlcj1jKHJlcCgtMTUsMTYpLHJlcCgxZS03LDE2KSxyZXAoLjEsMTYpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyPSBjKHJlcCgxNSwxNikscmVwKDAuOTksMTYpLHJlcCguOTksMTYpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPWxpc3QobG9naW5mbz1UUlVFLCBmb3J3YXJkPVRSVUUpKQ0Kc3RvcENsdXN0ZXIoY2wpDQoNCnRvYygpDQoNCnNhdmVSRFMob3B0aW1fcmVzdWx0LCBmaWxlPSJvcHRpbV9yZXN1bHRfdjA0LlJEUyIpDQoNCiMgb3B0aW1fcmVzdWx0IDwtIHJlYWRSRFMoIm9wdGltX3Jlc3VsdF92MDQuUkRTIikNCmBgYA0KDQoNCmBgYHtyfQ0KI3B1dCB0aGVzZSBuZXcgdmFscyBpbnRvc3BlY2llc19wYXJhbXMgYW5kIGdvIGJhY2sgdG8gdGhlIHRvcCBvZiB0aGlzIHBhZ2UgdG8gcmUtY2hlY2sgdGhlIGNhbGlicmF0aW9uIA0Kc3BlY2llc19wYXJhbXMocGFyYW1zX29wdGltKSRSX21heDwtMTBeb3B0aW1fcmVzdWx0JHBhclsxOjE2XQ0Kc3BlY2llc19wYXJhbXMocGFyYW1zX29wdGltKSRlcmVwcm88LW9wdGltX3Jlc3VsdCRwYXJbMTc6MzJdDQpzcGVjaWVzX3BhcmFtcyhwYXJhbXNfb3B0aW0pJGludGVyYWN0aW9uX3Jlc291cmNlIDwtb3B0aW1fcmVzdWx0JHBhclszMzo0OF0NCg0Kc3BlY2llc19wYXJhbXMocGFyYW1zX29wdGltKSRSX21heA0Kc3BlY2llc19wYXJhbXMocGFyYW1zX29wdGltKSRlcmVwcm8NCnNwZWNpZXNfcGFyYW1zKHBhcmFtc19vcHRpbSkkaW50ZXJhY3Rpb25fcmVzb3VyY2UNCmBgYA0KDQoNCg0KYGBge3J9DQpzaW1fdjE0IDwtIHByb2plY3QocGFyYW1zX29wdGltLCB0X21heCA9IDIwMDApDQpwbG90QmlvbWFzcyhzaW1fdjE0KQ0KYGBgDQoNCg0KYGBge3J9DQpwYXJhbXNfdjA4IDwtIHBhcmFtc19vcHRpbQ0KaW5pdGlhbE4ocGFyYW1zX3YwOCkgPC0gc2ltX3YxNEBuW2RpbShzaW1fdjE0QG4pWzFdLCxdDQpgYGANCg0KDQpgYGB7cn0NCnBhcmFtc190dW5lZF92MDcgPC0gdHVuZVBhcmFtcyhwYXJhbXNfdjA4KQ0KDQpwYXJhbXNfdHVuZWRfdjA3IDwtIHN0ZWFkeShwYXJhbXNfdHVuZWRfdjA3KQ0KDQpwYXJhbXNfdHVuZWRfdjA3QHNwZWNpZXNfcGFyYW1zJGVyZXBybw0KcGFyYW1zX3R1bmVkX3YwN0BzcGVjaWVzX3BhcmFtcyRSX21heA0KDQojIHNhdmVSRFMocGFyYW1zX3R1bmVkX3YwNywgZmlsZT0icGFyYW1zX29wdGltX3YwNF93X3BwXzEwMC5yZHMiKQ0KcGFyYW1zX3R1bmVkX3YwNyA8LSByZWFkUkRTKCJwYXJhbXMvcGFyYW1zX29wdGltX3YwNF93X3BwXzEwMC5yZHMiKQ0KYGBgDQoNCg0KYGBge3J9DQpzaW1fdjE1IDwtIHByb2plY3QocGFyYW1zX3R1bmVkX3YwNywgdF9tYXggPSAyMDAwKQ0KcGxvdEJpb21hc3Moc2ltX3YxNSkNCnBsb3REaWV0KHBhcmFtc190dW5lZF92MDcpDQpgYGANCg0KDQpgYGB7cn0NCmluaXRpYWxOKHBhcmFtc190dW5lZF92MDcpIDwtIHNpbV92MTVAbltkaW0oc2ltX3YxNUBuKVsxXSwsXQ0KDQpzaW1fdjE2IDwtIHByb2plY3QocGFyYW1zX3R1bmVkX3YwNywgdF9tYXggPSA1MDApDQpwbG90bHlCaW9tYXNzKHNpbV92MTYpDQpwbG90QmlvbWFzc09ic2VydmVkVnNNb2RlbChzaW1fdjE2KQ0KYGBgDQoNCmBgYHtyfQ0KcGFyYW1zX2xvb3AgPC0gcGFyYW1zX3R1bmVkX3YwNyB8Pg0KICAgIG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4gbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8Pg0KICAgIG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4gbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8Pg0KICAgIG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4gbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8Pg0KICAgIG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4gbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8Pg0KICAgIG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4gbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8Pg0KICAgIG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4gbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8Pg0KICAgIG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4gbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8Pg0KICAgIG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4gbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKSB8Pg0KICAgIG1hdGNoQmlvbWFzc2VzKCkgfD4gc3RlYWR5KCkgfD4gbWF0Y2hCaW9tYXNzZXMoKSB8PiBzdGVhZHkoKQ0KDQpwYXJhbXNfbG9vcEBzcGVjaWVzX3BhcmFtcyRlcmVwcm8NCmBgYA0KDQoNCmBgYHtyfQ0Kc2ltX3YxNyA8LSBwcm9qZWN0KHBhcmFtc19sb29wLCB0X21heCA9IDUwMCkNCnBsb3RseUJpb21hc3Moc2ltX3YxNykNCnBsb3RCaW9tYXNzT2JzZXJ2ZWRWc01vZGVsKHNpbV92MTcpDQojIHBsb3RCaW9tYXNzT2JzZXJ2ZWRWc01vZGVsQ3VzdG9tKHNpbV92MTcpDQpwbG90QmlvbWFzc1JlbGF0aXZlKHNpbV92MTcpDQpwbG90RGlldChwYXJhbXNfbG9vcCkNCmBgYA0KDQoNCg0KYGBge3J9DQpwYXJhbXNfbG9vcCA8LSBzdGVhZHkocGFyYW1zX2xvb3ApDQpgYGANClJlZHVjZSBpbnRlcmFjdGlvbiB3aXRoIHJlc291cmNlIGdyYWR1YWxseSB0byBzZWUgaWYgdGhhdCBjYW4gaW5jcmVhc2UgcHJlZGF0aW9uIG9uIGV1cGhhdXNpaWRzDQoNCg0KYGBge3J9DQpib3gucGFyYW1zIDwtIHBhcmFtc19sb29wDQoNCmJveC5wYXJhbXNAc3BlY2llc19wYXJhbXMkcHBtcl9taW5bYm94LnBhcmFtc0BzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJiYWxlZW4gd2hhbGVzIl0gIDwtIDRlNg0KYm94LnBhcmFtc0BzcGVjaWVzX3BhcmFtcyRwcG1yX21heFtib3gucGFyYW1zQHNwZWNpZXNfcGFyYW1zJHNwZWNpZXMgPT0gImJhbGVlbiB3aGFsZXMiXSA8LTVlNg0KIyBib3gucGFyYW1zQHNwZWNpZXNfcGFyYW1zJHByZWRfa2VybmVsX3R5cGVbYm94LnBhcmFtc0BzcGVjaWVzX3BhcmFtcyRzcGVjaWVzID09ICJiYWxlZW4gd2hhbGVzIl0gPC0gImJveCINCg0KYm94LnBhcmFtcyA8LSBzZXRQYXJhbXMoYm94LnBhcmFtcykNCmBgYA0KDQoNCg0KDQpgYGB7cn0NCnBhcmFtc192MTUgPC0gc3RlYWR5KGJveC5wYXJhbXMpDQpwYXJhbXNfdjE1IDwtIHR1bmVQYXJhbXMoYm94LnBhcmFtcykNCmBgYA0KDQoNCg0KDQoNCg0KDQo=